ZQuest Classic Coverage Report


Directory: src/
File: src/gui/jwin.cpp
Date: 2025-11-21 07:35:34
Exec Total Coverage
Lines: 104 5712 1.8%
Functions: 14 150 9.3%
Branches: 47 4461 1.1%

Line Branch Exec Source
1 #include <ctype.h>
2 #include <cstring>
3 #include "base/zapp.h"
4 #include "base/zc_alleg.h"
5 #include <allegro/internal/aintern.h>
6 #include "gui/jwin.h"
7 #include "base/zdefs.h"
8 #include "gui/editbox.h"
9 #include <iostream>
10 #include <sstream>
11 #include "base/zsys.h"
12 #include <stdio.h>
13 #include "base/util.h"
14 #include "pal.h"
15 #include "gui/tabpanel.h"
16 #include "gui/text_field.h"
17 #include "dialog/info.h"
18 #include "drawing.h"
19 using namespace util;
20 using std::string;
21 using std::istringstream;
22
23 void update_hw_screen();
24 extern int32_t zq_screen_w, zq_screen_h;
25 extern int32_t joystick_index;
26 int CheckerCol1 = 7, CheckerCol2 = 8;
27
28 int32_t abc_patternmatch = 1;
29
30 char abc_keypresses[1024] = {0};
31 void wipe_abc_keypresses() { memset(abc_keypresses, 0, 1024); }
32
33 /* these are provided for external use */
34 int32_t jwin_colors[jcMAX] =
35 {
36 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
37 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
38 };
39
40 int32_t scheme[jcMAX] =
41 {
42 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
43 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
44 };
45
46 int32_t jwin_pal[jcMAX] = {0};
47
48 // A pointer to this variable is used to identify the DIALOG belonging to
49 // the DialogRunner. It isn't used for anything else.
50 char newGuiMarker;
51
52 int32_t new_gui_event(DIALOG* d, guiEvent event)
53 {
54 for(int32_t i = 0; true; --d, ++i)
55 {
56 if(d->dp3 == &newGuiMarker)
57 {
58 d->d1 = i;
59 return d->proc(MSG_GUI_EVENT, d, event);
60 }
61 }
62
63 return -1;
64 }
65
66 void close_new_gui_dlg(DIALOG* d);
67
68 int32_t bound(int32_t x,int32_t low,int32_t high)
69 {
70 if(x<low) x=low;
71
72 if(x>high) x=high;
73
74 return x;
75 }
76 /*
77 float bound(float x,float low,float high)
78 {
79 if(x<low) x=low;
80 if(x>high) x=high;
81 return x;
82 }
83 */
84
85 int32_t get_selected_tab(TABPANEL* panel)
86 {
87 for(int32_t i=0; panel[i].text; ++i)
88 {
89 if((panel[i].flags&D_SELECTED)!=0)
90 return i;
91 }
92 return -1;
93 }
94
95 /* jwin_set_colors:
96 * Loads a set of colors in 0xRRGGBB or 256-color-indexed format
97 * into the current color scheme using the appropriate color depth
98 * conversions.
99 */
100 118 void jwin_set_colors(int32_t *colors)
101 {
102 118 int32_t i = 0;
103
104
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 if(bitmap_color_depth(screen) == 8)
105 {
106 // use color indices
107
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 2478 times.
2596 for(; i<jcMAX; i++)
108 2478 scheme[i] = colors[i];
109 118 }
110 else
111 {
112 // 0xRRGGBB format
113 for(; i<jcMAX; i++)
114 scheme[i] = makecol(colors[i]>>16, (colors[i]>>8)&0xFF, colors[i]&0xFF);
115 }
116 118 }
117
118 /* jwin_set_dialog_color:
119 * Sets the foreground and background colors of all the objects in a dialog.
120 *
121 * Needs work!
122 */
123 void jwin_set_dialog_color(DIALOG *dialog)
124 {
125 int32_t c;
126
127 for(c=0; dialog[c].proc; c++)
128 {
129 dialog[c].fg = scheme[jcMEDDARK];
130 dialog[c].bg = scheme[jcBOX];
131 }
132 }
133
134 /* jwin_draw_frame:
135 * Draws a frame using the specified style.
136 */
137 void jwin_draw_frame(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t style)
138 {
139 optional<int> c1,c2,c3,c4;
140
141 switch(style)
142 {
143 case FR_INVIS:
144 return;
145 case FR_BOX:
146 c1 = jcLIGHT;
147 c2 = jcMEDLT;
148 c3 = jcMEDDARK;
149 c4 = jcDARK;
150 break;
151
152 case FR_INV:
153 c1 = jcDARK;
154 c2 = jcMEDDARK;
155 c3 = jcMEDLT;
156 c4 = jcLIGHT;
157 break;
158
159 case FR_DEEP:
160 c1 = jcMEDDARK;
161 c2 = jcDARK;
162 c3 = jcMEDLT;
163 c4 = jcLIGHT;
164 break;
165
166 case FR_DARK:
167 c1 = jcDARK;
168 c2 = jcMEDDARK;
169 c3 = jcMEDDARK;
170 c4 = jcDARK;
171 break;
172
173 case FR_ETCHED:
174 c1 = jcMEDDARK;
175 c2 = jcLIGHT;
176 c3 = jcMEDDARK;
177 c4 = jcLIGHT;
178 break;
179
180 case FR_MEDDARK:
181 c1 = jcMEDDARK;
182 c2 = jcBOX;
183 c3 = jcBOX;
184 c4 = jcMEDDARK;
185 break;
186
187 case FR_MENU:
188 c1 = jcLIGHT;
189 c4 = jcMEDDARK;
190 break;
191 case FR_MENU_INV:
192 c1 = jcMEDDARK;
193 c2 = jcMEDDARK;
194 c3 = jcLIGHT;
195 c4 = jcLIGHT;
196 break;
197
198 case FR_WIN:
199 default:
200 c1 = jcMEDLT;
201 c2 = jcLIGHT;
202 c3 = jcMEDDARK;
203 c4 = jcDARK;
204 break;
205 }
206
207 if(c1) c1 = scheme[*c1];
208 if(c2) c2 = scheme[*c2];
209 if(c3) c3 = scheme[*c3];
210 if(c4) c4 = scheme[*c4];
211 switch (style)
212 {
213 case FR_RED:
214 c1 = 0xE4;
215 c2 = 0xEC;
216 c3 = 0xE4;
217 c4 = 0xEC;
218 break;
219 case FR_GREEN:
220 c1 = 0xE2;
221 c2 = 0xEA;
222 c3 = 0xE2;
223 c4 = 0xEA;
224 break;
225 }
226 if(c1)
227 {
228 hline(dest, vbound(x,0,dest->w-1), vbound(y,0,dest->h-1) , vbound(x+w-2, 0,dest->w-1), *c1);
229 vline(dest, vbound(x,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-2, 0, dest->h-1), *c1);
230 }
231 if(c2)
232 {
233 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(x+w-3,0,dest->w-1), *c2);
234 vline(dest, vbound(x+1,0,dest->w-1), vbound(y+2,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c2);
235 }
236 if(c3)
237 {
238 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+h-2,0,dest->h-1), vbound(x+w-2,0,dest->w-1), *c3);
239 vline(dest, vbound(x+w-2,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c3);
240 }
241 if(c4)
242 {
243
244 hline(dest, vbound(x,0,dest->w-1), vbound(y+h-1,0,dest->h-1), vbound(x+w-1,0, dest->w-1), *c4);
245 vline(dest, vbound(x+w-1,0,dest->w-1), vbound(y,0,dest->h-1), vbound(y+h-2,0,dest->h-1), *c4);
246 }
247 }
248 void jwin_draw_frag_frame(BITMAP* dest, int x1, int y1, int w, int h, int fw, int fh, int style)
249 {
250 int c1,c2,c3,c4;
251
252 switch(style)
253 {
254 case FR_BOX:
255 c1 = jcLIGHT;
256 c2 = jcMEDLT;
257 c3 = jcMEDDARK;
258 c4 = jcDARK;
259 break;
260
261 case FR_INV:
262 c1 = jcDARK;
263 c2 = jcMEDDARK;
264 c3 = jcMEDLT;
265 c4 = jcLIGHT;
266 break;
267
268 case FR_DEEP:
269 c1 = jcMEDDARK;
270 c2 = jcDARK;
271 c3 = jcMEDLT;
272 c4 = jcLIGHT;
273 break;
274
275 case FR_DARK:
276 c1 = jcDARK;
277 c2 = jcMEDDARK;
278 c3 = jcMEDDARK;
279 c4 = jcDARK;
280 break;
281
282 case FR_ETCHED:
283 c1 = jcMEDDARK;
284 c2 = jcLIGHT;
285 c3 = jcMEDDARK;
286 c4 = jcLIGHT;
287 break;
288
289 case FR_MEDDARK:
290 c1 = jcMEDDARK;
291 c2 = jcBOX;
292 c3 = jcBOX;
293 c4 = jcMEDDARK;
294 break;
295
296 case FR_WIN:
297 default:
298 c1 = jcMEDLT;
299 c2 = jcLIGHT;
300 c3 = jcMEDDARK;
301 c4 = jcDARK;
302 break;
303 }
304
305 int xc = x1+fw-1;
306 int yc = y1+fh-1;
307 int x2 = x1+w-1;
308 int y2 = y1+h-1;
309
310 rectfill(dest, x1, y1, x2, yc, vc(0));
311 rectfill(dest, x1, yc, xc, y2, vc(0));
312
313 hline(dest, x1-2, y1-2, x2+2, scheme[c1]);
314 hline(dest, x1-1, y1-1, x2+1, scheme[c2]);
315
316 vline(dest, x1-2, y1-2, y2+2, scheme[c1]);
317 vline(dest, x1-1, y1-1, y2+1, scheme[c2]);
318
319 hline(dest, x1-2, y2+2, xc+2, scheme[c3]);
320 hline(dest, x1-1, y2+1, xc+1, scheme[c4]);
321
322 vline(dest, x2+2, y1-2, yc+2, scheme[c3]);
323 vline(dest, x2+1, y1-1, yc+1, scheme[c4]);
324
325 hline(dest, xc+2, yc+2, x2+2, scheme[c3]);
326 hline(dest, xc+1, yc+1, x2+1, scheme[c4]);
327
328 vline(dest, xc+2, yc+2, y2+2, scheme[c3]);
329 vline(dest, xc+1, yc+1, y2+1, scheme[c4]);
330 }
331 void jwin_draw_minimap_frame(BITMAP *dest,int x,int y,int w,int h,int scrsz,int style)
332 {
333 jwin_draw_frag_frame(dest,x,y,w,h,scrsz*8,scrsz*8,style);
334 }
335
336 /* jwin_draw_win:
337 * Draws a window -- a box with a frame.
338 */
339 void jwin_draw_win(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t frame)
340 {
341 rectfill(dest,zc_max(x,0),zc_max(y,0),zc_min(x+w-1, dest->w-1),zc_min(y+h-1, dest->h-1),scheme[jcBOX]);
342 jwin_draw_frame(dest, x, y, w, h, frame);
343 }
344
345 /* jwin_draw_button:
346 * Helper function for buttons.
347 * Draws a box with a frame that depends on "state":
348 * 0: normal border (slightly different than window border)
349 * 1: inverted border
350 * 2: dark border
351 * 3: medium dark border
352 */
353 void jwin_draw_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t state,int32_t type)
354 {
355 int32_t frame = FR_BOX;
356
357 if(type==1)
358 {
359 frame=FR_WIN;
360 }
361
362 switch(state)
363 {
364 case 1:
365 frame = FR_INV;
366 break;
367
368 case 2:
369 frame = FR_DARK;
370 break;
371
372 case 3:
373 frame = FR_MEDDARK;
374 break;
375 }
376
377 jwin_draw_win(dest, x, y, w, h, frame);
378 }
379
380 /* mix_value:
381 * Returns a mix of the values c1 and c2 with pos==0 being c1,
382 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
383 */
384 int32_t mix_value(int32_t c1,int32_t c2,int32_t pos,int32_t max)
385 {
386 if(max<=0)
387 return c1;
388
389 return (c2 - c1) * pos / max + c1;
390 }
391
392 /* mix_color:
393 * Returns a mix of the colors c1 and c2 with pos==0 being c1,
394 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
395 *
396 static int32_t mix_color(int32_t c1,int32_t c2,int32_t pos,int32_t max)
397 {
398 int32_t c;
399
400 if(bitmap_color_depth(screen) == 8)
401 c = mix_value(c1, c2, pos, max);
402 else
403 {
404 int32_t r = mix_value(getr(c1), getr(c2), pos, max);
405 int32_t g = mix_value(getg(c1), getg(c2), pos, max);
406 int32_t b = mix_value(getb(c1), getb(c2), pos, max);
407 c = makecol(r,g,b);
408 }
409
410 return c;
411 }
412 */
413
414 char *shorten_string(char *dest, char const* src, FONT *usefont, int32_t maxchars, int32_t maxwidth)
415 {
416 strncpy(dest,src,maxchars);
417 dest[maxchars-1]='\0';
418 int32_t len=(int32_t)strlen(dest);
419 int32_t width=text_length(usefont, dest);
420 dest[len]=0;
421
422 while(width>maxwidth && len>4)
423 {
424 dest[len-4] = '.';
425 dest[len-3] = '.';
426 dest[len-2] = '.';
427 dest[len-1] = 0;
428 len--;
429 width=text_length(usefont, dest);
430 }
431
432 return dest;
433 }
434
435 void jwin_draw_titlebar(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, bool draw_button, bool helpbtn)
436 {
437 char buf[512];
438 int32_t len = (int32_t)strlen(str);
439 int32_t length = text_length(font,str);
440 int32_t height = text_height(font);
441
442 int32_t tx = x + 2;
443 int32_t ty = y + (h-height)/2;
444 PALETTE temp_pal;
445 get_palette(temp_pal);
446 dither_rect(dest, &temp_pal, x, y, x+w-1, y+h-1,
447 makecol15(temp_pal[scheme[jcTITLEL]].r,
448 temp_pal[scheme[jcTITLEL]].g,
449 temp_pal[scheme[jcTITLEL]].b),
450 makecol15(temp_pal[scheme[jcTITLER]].r,
451 temp_pal[scheme[jcTITLER]].g,
452 temp_pal[scheme[jcTITLER]].b),
453 scheme[jcTITLEL], scheme[jcTITLER]);
454
455
456 if(len>509)
457 len=509;
458
459 strncpy(buf,str,len);
460 buf[len]=0;
461
462 // this part needs work
463
464 if(length>w-20)
465 {
466 while(length>w-20 && len>1)
467 {
468 buf[len-4] = '.';
469 buf[len-3] = '.';
470 buf[len-2] = '.';
471 buf[len-1] = 0;
472 len--;
473 length = text_length(font,buf);
474 }
475 }
476
477 textout_ex(dest,font,buf,tx,ty,scheme[jcTITLEFG],-1);
478
479 if(draw_button)
480 {
481 draw_x_button(dest, x + w - 18, y+2, 0);
482 }
483
484 if(helpbtn)
485 {
486 draw_question_button(dest, x + w - (draw_button ? 36 : 18), y+2, 0);
487 }
488
489 }
490
491 void draw_question_button(BITMAP* dest, int32_t x, int32_t y, int32_t state)
492 {
493 int32_t c = scheme[jcBOXFG];
494
495 jwin_draw_button(dest,x,y,16,14,state,0);
496 x += 4 + (state?1:0);
497 y += 3 + (state?1:0);
498
499 line(dest, x+2, y+0, x+5, y+0, c);
500 line(dest, x+1, y+1, x+2, y+1, c);
501 line(dest, x+5, y+1, x+6, y+1, c);
502 line(dest, x+4, y+2, x+5, y+2, c);
503 line(dest, x+3, y+3, x+4, y+3, c);
504 line(dest, x+3, y+4, x+4, y+4, c);
505 line(dest, x+3, y+6, x+4, y+6, c);
506 line(dest, x+3, y+7, x+4, y+7, c);
507 }
508
509 void draw_x_button(BITMAP *dest, int32_t x, int32_t y, int32_t state)
510 {
511 int32_t c = scheme[jcBOXFG];
512
513 jwin_draw_button(dest,x,y,16,14,state,0);
514 x += 4 + (state?1:0);
515 y += 3 + (state?1:0);
516
517 line(dest,x, y, x+6,y+6,c);
518 line(dest,x+1,y, x+7,y+6,c);
519 line(dest,x, y+6,x+6,y, c);
520 line(dest,x+1,y+6,x+7,y, c);
521 }
522
523 void draw_arrow(BITMAP *dest, int c, int x, int y, int h, bool up, bool center)
524 {
525 if(!center)
526 x += h-1;
527 for(int i = 0; i<h; i++)
528 hline(dest, x-(up?i:h-i-1), y+i, x+(up?i:h-i-1), c);
529 }
530 void draw_arrow_horz(BITMAP *dest, int c, int x, int y, int w, bool left, bool center)
531 {
532 if(!center)
533 y += w-1;
534 for(int i = 0; i<w; i++)
535 vline(dest, x+i, y-(left?i:w-i-1), y+(left?i:w-i-1), c);
536 }
537 void draw_arrow_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
538 {
539 int32_t c = scheme[jcDARK];
540 int32_t ah = zc_min(h/3, 5);
541 int32_t i = 0;
542
543 jwin_draw_button(dest,x,y,w,h,state,1);
544 x += w/2 - (state?0:1);
545 y += (h-ah)/2 + (state?1:0);
546
547 for(; i<ah; i++)
548 {
549 hline(dest, x-(up?i:ah-i-1), y+i, x+(up?i:ah-i-1), c);
550 }
551 }
552
553 void draw_arrow_button_horiz(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
554 {
555 int32_t c = scheme[jcDARK];
556 int32_t aw = zc_min(w/3, 5);
557 int32_t i = 0;
558
559 jwin_draw_button(dest,x,y,w,h,state,1);
560 y += h/2 - (state?0:1);
561 x += (w-aw)/2 + (state?1:0);
562
563 for(; i<aw; i++)
564 {
565 vline(dest, x+i,y-(up?i:aw-i-1), y+(up?i:aw-i-1), c);
566 }
567 }
568
569 int32_t mouse_in_rect(int32_t x,int32_t y,int32_t w,int32_t h)
570 {
571 return ((gui_mouse_x() >= x) && (gui_mouse_y() >= y) &&
572 (gui_mouse_x() < x + w) && (gui_mouse_y() < y + h));
573 }
574
575 static int32_t jwin_do_x_button(BITMAP *dest, int32_t x, int32_t y)
576 {
577 int32_t down=0, last_draw = 0;
578
579 while(gui_mouse_b())
580 {
581 down = mouse_in_rect(x,y,16,14);
582
583 if(down!=last_draw)
584 {
585 draw_x_button(dest,x,y,down);
586 last_draw = down;
587 }
588
589 /* let other objects continue to animate */
590 broadcast_dialog_message(MSG_IDLE, 0);
591 rest(1);
592 }
593
594 if(down)
595 {
596 draw_x_button(dest,x,y,0);
597 }
598
599 return down;
600 }
601
602 /* dotted_rect:
603 * Draws a dotted rectangle, for showing an object has the input focus.
604 */
605 void dotted_rect(BITMAP *dest, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
606 {
607 int32_t x = ((x1+y1) & 1) ? 1 : 0;
608 int32_t c;
609
610 //acquire the bitmap ourselves, because locking a surface within each call is *SLOW AS BALLS* -DD
611 acquire_bitmap(dest);
612
613 for(c=x1; c<=x2; c++)
614 {
615 putpixel(dest, c, y1, (((c+y1) & 1) == x) ? fg : bg);
616 putpixel(dest, c, y2, (((c+y2) & 1) == x) ? fg : bg);
617 }
618
619 for(c=y1+1; c<y2; c++)
620 {
621 putpixel(dest, x1, c, (((c+x1) & 1) == x) ? fg : bg);
622 putpixel(dest, x2, c, (((c+x2) & 1) == x) ? fg : bg);
623 }
624
625 release_bitmap(dest);
626
627 }
628
629 static void _dotted_rect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
630 {
631 dotted_rect(screen, x1, y1, x2, y2, fg, bg);
632 }
633
634 static bool no_hline = false;
635 /* gui_textout_ln:
636 * Wrapper function for drawing text to the screen, which interprets the
637 * & character as an underbar for displaying keyboard shortcuts. Returns
638 * the width of the output string in pixels.
639 *
640 * Handles '\n' characters.
641 */
642 6 int32_t gui_textout_ln(BITMAP *bmp, FONT *f, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
643 {
644 char tmp[1024];
645 6 int32_t c = 0;
646 int32_t len;
647 6 int32_t pix_len = 0;
648 6 int32_t max_len = 0;
649 int32_t hline_pos;
650 6 int32_t xx = x;
651 6 bool is_scr = bmp == screen;
652
653
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 6 times.
21 while(s[c])
654 {
655 15 len = 0;
656 15 hline_pos = -1;
657
658
4/4
✓ Branch 0 taken 798 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 798 times.
804 for(; (s[c]) && (len<(int32_t)(sizeof(tmp)-1)); c++)
659 {
660
2/2
✓ Branch 0 taken 789 times.
✓ Branch 1 taken 9 times.
798 if(s[c] == '\n')
661 {
662 9 c++;
663 9 break;
664 }
665
2/4
✓ Branch 0 taken 789 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 789 times.
✗ Branch 3 not taken.
789 else if(!no_hline && s[c] == '&')
666 {
667 if(s[c+1] != '&')
668 hline_pos = len;
669 else
670 {
671 tmp[len++] = '&';
672 c++;
673 }
674 }
675 else
676 789 tmp[len++] = s[c];
677 789 }
678
679 15 tmp[len] = 0;
680 15 pix_len = text_length(f, tmp);
681
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (pix_len > max_len) max_len = pix_len;
682 15 x = xx;
683
684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if(pos==1) //center
685 {
686 x -= pix_len / 2;
687 }
688
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 else if(pos==2) //right
689 {
690 x -= pix_len;
691 }
692
693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if(bmp)
694 {
695 15 textout_ex(bmp, f, tmp, x, y, color,bg);
696
697
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if(hline_pos >= 0)
698 {
699 int32_t i;
700 i = tmp[hline_pos];
701 tmp[hline_pos] = 0;
702 hline_pos = text_length(f, tmp);
703 tmp[0] = i;
704 tmp[1] = 0;
705 i = text_length(f, tmp);
706 hline(bmp, x+hline_pos, y+text_height(f)-gui_font_baseline, x+hline_pos+i-1, color);
707 }
708 15 }
709
710 15 y += text_height(f);
711 }
712 6 return max_len;
713 }
714
715 6 int32_t gui_textout_ln(BITMAP *bmp, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
716 {
717 6 return gui_textout_ln(bmp, font, s, x, y, color, bg, pos);
718 }
719
720 int32_t gui_text_width(FONT *f, const char *s)
721 {
722 return gui_textout_ln(NULL, f, (uint8_t*)s, 0, 0, 0, 0, 0);
723 }
724
725 6 int32_t count_newline(uint8_t *s)
726 {
727 6 int32_t cnt = 0;
728
2/2
✓ Branch 0 taken 798 times.
✓ Branch 1 taken 6 times.
804 for(int32_t q = 0; s[q] != 0; ++q)
729 {
730
2/2
✓ Branch 0 taken 789 times.
✓ Branch 1 taken 9 times.
798 if(s[q] == '\n') ++cnt;
731 798 }
732 6 return cnt;
733 }
734
735 6 int32_t gui_textheight(FONT* f, uint8_t *s)
736 {
737 6 return text_height(f) * (count_newline(s) + 1);
738 }
739
740 6 int32_t gui_textheight(uint8_t* s)
741 {
742 6 return gui_textheight(font, s);
743 }
744
745 /* typedef for the listbox callback functions */
746 typedef char *(*getfuncptr)(int32_t, int32_t *);
747
748 /* event handler that closes a dialog */
749 int32_t close_dlg()
750 {
751 return D_CLOSE;
752 }
753
754 int32_t jwin_frame_proc(int32_t msg, DIALOG *d, int32_t c)
755 {
756 //these are here to bypass compiler warnings about unused arguments
757 c=c;
758
759 if(msg == MSG_DRAW)
760 {
761 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
762 }
763
764 return D_O_K;
765 }
766
767 int32_t jwin_guitest_proc(int32_t msg, DIALOG *d, int32_t c)
768 {
769 //these are here to bypass compiler warnings about unused arguments
770 c=c;
771
772 if(msg == MSG_DRAW)
773 {
774 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
775 }
776
777 return D_O_K;
778 }
779
780 /* jwin_win_proc:
781 * Draws a box with a frame. Use dp for a title string. If dp is NULL,
782 * it won't draw a title bar. If the D_EXIT flag is set, it will also
783 * draw an "X" button on the title bar that can be used to close the
784 * dialog.
785 * If d->dp3 is non-null, it will be read as a help text string, and
786 * a ? button will be drawn, that upon clicking will display the helptext.
787 */
788 int32_t jwin_win_proc(int32_t msg, DIALOG *d, int32_t c)
789 {
790 //these are here to bypass compiler warnings about unused arguments
791 c=c;
792
793 rest(1);
794 static bool skipredraw = false;
795
796 switch(msg)
797 {
798 case MSG_DRAW:
799 if(skipredraw)
800 {
801 skipredraw = false;
802 break;
803 }
804 jwin_draw_win(screen, d->x, d->y, d->w, d->h, FR_WIN);
805
806 if(d->dp)
807 {
808 FONT *oldfont = font;
809
810 if(d->dp2)
811 {
812 font = (FONT*)d->dp2;
813 }
814
815 jwin_draw_titlebar(screen, d->x+3, d->y+3, d->w-6, 18, (char*)d->dp, d->flags & D_EXIT, d->dp3!=NULL);
816 font = oldfont;
817 }
818 break;
819
820 case MSG_WANTFOCUS:
821 if(gui_mouse_b())
822 return D_WANTFOCUS|D_REDRAW;
823 else return D_O_K;
824 case MSG_GOTFOCUS:
825 case MSG_LOSTFOCUS:
826 skipredraw = true;
827 return D_O_K;
828
829 case MSG_CLICK:
830 {
831 if((d->flags & D_EXIT) && mouse_in_rect(d->x+d->w-21, d->y+5, 16, 14))
832 {
833 if(jwin_do_x_button(screen, d->x+d->w-21, d->y+5))
834 {
835 GUI_EVENT(d, geCLOSE);
836 return D_CLOSE;
837 }
838 }
839 if(char const* helpstr = (char const*)d->dp3)
840 {
841 if(mouse_in_rect(d->x+d->w-((d->flags&D_EXIT)?39:21), d->y+5, 16, 14))
842 {
843 broadcast_dialog_message(MSG_DRAW,0);
844 InfoDialog("Info", helpstr).show();
845 }
846 }
847 }
848 break;
849 }
850
851 return D_O_K;
852 }
853
854 /* jwin_text_proc:
855 * Simple dialog procedure: draws the text string which is pointed to by dp.
856 *
857 * Handles '\n' characters.
858 */
859 6 int32_t jwin_text_proc(int32_t msg, DIALOG *d, int32_t)
860 {
861 ASSERT(d);
862
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
863
864
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 switch(msg)
865 {
866 case MSG_START:
867 {
868 6 FONT *oldfont = font;
869
870
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(d->dp2)
871 {
872 font = (FONT*)d->dp2;
873 }
874
875 6 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
876 6 d->h=gui_textheight((uint8_t *)d->dp);
877
878 6 font = oldfont;
879 6 break;
880 }
881 case MSG_DRAW:
882 {
883 FONT *oldfont = font;
884
885 if(d->dp2)
886 {
887 font = (FONT*)d->dp2;
888 }
889
890 if(d->flags & D_DISABLED)
891 {
892 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
893 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 0);
894 }
895 else
896 {
897 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 0);
898 }
899
900 font = oldfont;
901 break;
902 }
903 }
904
905 6 return D_O_K;
906 }
907
908 int32_t jwin_ctext_proc(int32_t msg, DIALOG *d, int32_t)
909 {
910 ASSERT(d);
911 static BITMAP *dummy=create_bitmap_ex(8, 320, 240);
912
913 switch(msg)
914 {
915 case MSG_START:
916 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
917 break;
918
919 case MSG_DRAW:
920 FONT *oldfont = font;
921
922 if(d->dp2)
923 {
924 font = (FONT*)d->dp2;
925 }
926
927 if(d->flags & D_DISABLED)
928 {
929 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 1);
930 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 1);
931 }
932 else
933 {
934 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 1);
935 }
936
937 font = oldfont;
938 break;
939 }
940
941 return D_O_K;
942 }
943
944 int32_t jwin_rtext_proc(int32_t msg, DIALOG *d, int32_t)
945 {
946 ASSERT(d);
947 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
948
949 switch(msg)
950 {
951 case MSG_START:
952 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 2);
953 break;
954
955 case MSG_DRAW:
956 FONT *oldfont = font;
957
958 if(d->dp2)
959 {
960 font = (FONT*)d->dp2;
961 }
962
963 if(d->flags & D_DISABLED)
964 {
965 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 2);
966 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 2);
967 }
968 else
969 {
970 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 2);
971 }
972
973 font = oldfont;
974 break;
975 }
976
977 return D_O_K;
978 }
979
980 int32_t d_ctext2_proc(int32_t msg, DIALOG *d, int32_t c)
981 {
982 auto ret = d_ctext_proc(msg, d, c);
983 return ret;
984 }
985
986 int32_t new_text_proc(int32_t msg, DIALOG *d, int32_t c)
987 {
988 BITMAP* oldscreen = screen;
989 if(msg==MSG_DRAW)
990 {
991 if(d->flags & D_HIDDEN) return D_O_K;
992 screen = create_bitmap_ex(8,oldscreen->w,oldscreen->h);
993 clear_bitmap(screen);
994 set_clip_rect(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1);
995 }
996 int32_t ret = D_O_K;
997 int32_t w = d->w, h = d->h, x = d->x, y = d->y;
998 if(d->d2) no_hline = true;
999 switch(d->d1)
1000 {
1001 case 0:
1002 ret = jwin_text_proc(msg, d, c);
1003 break;
1004 case 1:
1005 d->x += d->w/2;
1006 ret = jwin_ctext_proc(msg, d, c);
1007 break;
1008 case 2:
1009 d->x += d->w - 1;
1010 ret = jwin_rtext_proc(msg, d, c);
1011 break;
1012 }
1013 no_hline = false;
1014 d->w = w;
1015 d->h = h;
1016 d->x = x;
1017 d->y = y;
1018 if(msg==MSG_DRAW)
1019 {
1020 masked_blit(screen, oldscreen, d->x, d->y, d->x, d->y, d->w, d->h);
1021 destroy_bitmap(screen);
1022 screen = oldscreen;
1023 }
1024 if(msg==MSG_WANTFOCUS && gui_mouse_b())
1025 ret |= D_WANTFOCUS|D_REDRAW;
1026 return ret;
1027 }
1028
1029 /* draw_text_button:
1030 * Helper for jwin_button_proc.
1031 */
1032 void jwin_draw_text_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, int32_t flags, bool show_dotted_rect)
1033 {
1034 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1035
1036 if(flags & D_SELECTED)
1037 {
1038 jwin_draw_button(dest, x, y, w, h, 2, 0);
1039 flags &= ~D_DISABLED;
1040 }
1041 else if(!(flags & D_GOTFOCUS))
1042 jwin_draw_button(dest, x, y, w, h, 0, 0);
1043 else
1044 {
1045 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1046 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1047 }
1048
1049 bool drawstring = true;
1050 if(str[1]==0 && byte(str[0]) >= 0x80)
1051 {
1052 drawstring = false;
1053 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1054 int aw = w/4, ah = h/4;
1055 int woff = (aw/2)+1, hoff = (ah/2)+1;
1056 int x1 = x+w/2, x2 = x+(w-aw)/2;
1057 int y1 = y+(h-aw)/2, y2 = y+h/2;
1058 switch(byte(str[0]))
1059 {
1060 case 0x88:
1061 draw_arrow(dest, col, x1, y1, ah, true, true);
1062 break;
1063 case 0x89:
1064 draw_arrow(dest, col, x1, y1, ah, false, true);
1065 break;
1066 case 0x8A:
1067 draw_arrow_horz(dest, col, x2, y2, aw, true, true);
1068 break;
1069 case 0x8B:
1070 draw_arrow_horz(dest, col, x2, y2, aw, false, true);
1071 break;
1072 case 0x98:
1073 draw_arrow(dest, col, x1, y1-hoff, ah, false, true);
1074 draw_arrow(dest, col, x1, y1+hoff, ah, true, true);
1075 break;
1076 case 0x99:
1077 draw_arrow(dest, col, x1, y1-hoff, ah, true, true);
1078 draw_arrow(dest, col, x1, y1+hoff, ah, false, true);
1079 break;
1080 case 0x9A:
1081 draw_arrow_horz(dest, col, x2-woff, y2, aw, false, true);
1082 draw_arrow_horz(dest, col, x2+woff, y2, aw, true, true);
1083 break;
1084 case 0x9B:
1085 draw_arrow_horz(dest, col, x2-woff, y2, aw, true, true);
1086 draw_arrow_horz(dest, col, x2+woff, y2, aw, false, true);
1087 break;
1088 default: drawstring = true;
1089 }
1090 }
1091 if(drawstring)
1092 {
1093 if(!(flags & D_DISABLED))
1094 gui_textout_ex(dest, str, x+w/2+g, y+(h-text_height(font))/2+g, scheme[jcBOXFG], -1, TRUE);
1095 else
1096 {
1097 gui_textout_ex(dest, str, x+w/2+1,y+(h-text_height(font))/2+1, scheme[jcLIGHT], -1, TRUE);
1098 gui_textout_ex(dest, str, x+w/2, y+(h-text_height(font))/2, scheme[jcDISABLED_FG], -1, TRUE);
1099 }
1100 }
1101
1102 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1103 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1104 }
1105
1106 int icon_proportion(int icon,int s1,int s2)
1107 {
1108 int sz = round(sqrt(zc_min(s1,s2))*1.25);
1109 switch(icon)
1110 {
1111 case BTNICON_STOPSQUARE:
1112 sz += 4;
1113 break;
1114 case BTNICON_GEAR:
1115 sz *= 3;
1116 break;
1117 case BTNICON_TRASH:
1118 sz *= 3;
1119 break;
1120 case BTNICON_PLUS:
1121 case BTNICON_MINUS:
1122 sz += 4;
1123 break;
1124 }
1125 return sz;
1126 }
1127 void jwin_draw_icon_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int icon, int32_t flags, bool show_dotted_rect)
1128 {
1129 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1130
1131 if(flags & D_SELECTED)
1132 jwin_draw_button(dest, x, y, w, h, 2, 0);
1133 else if(!(flags & D_GOTFOCUS))
1134 jwin_draw_button(dest, x, y, w, h, 0, 0);
1135 else
1136 {
1137 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1138 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1139 }
1140
1141 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1142 jwin_draw_icon(dest,x+w/2,y+h/2,col,icon,icon_proportion(icon,w,h),true);
1143
1144 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1145 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1146 }
1147 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int asz, bool center)
1148 {
1149 jwin_draw_icon(dest,x,y,col,icon,asz,asz,center);
1150 }
1151 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int aw, int ah, bool center)
1152 {
1153 int w2 = aw, h2 = ah;
1154 int sz = zc_min(aw,ah);
1155 switch(icon)
1156 {
1157 case BTNICON_ARROW_LEFT2:
1158 case BTNICON_ARROW_RIGHT2:
1159 aw *= 2;
1160 ah = aw*2-1;
1161 break;
1162 case BTNICON_ARROW_LEFT3:
1163 case BTNICON_ARROW_RIGHT3:
1164 aw *= 3;
1165 ah = aw*2-1;
1166 break;
1167 case BTNICON_ARROW_UP:
1168 case BTNICON_ARROW_DOWN:
1169 case BTNICON_CONTRACT_VERT:
1170 case BTNICON_EXPAND_VERT:
1171 aw = ah*2-1;
1172 break;
1173 case BTNICON_ARROW_LEFT:
1174 case BTNICON_ARROW_RIGHT:
1175 case BTNICON_CONTRACT_HORZ:
1176 case BTNICON_EXPAND_HORZ:
1177 ah = aw*2-1;
1178 break;
1179 case BTNICON_STOPSQUARE:
1180 aw = ah = sz;
1181 break;
1182 case BTNICON_PLUS:
1183 if(!(sz%2)) ++sz;
1184 aw = ah = w2 = h2 = sz;
1185 w2 = zc_max(1, w2/3);
1186 h2 = zc_max(1, h2/3);
1187 if(!(h2%2)) ++h2;
1188 if(!(w2%2)) ++w2;
1189 break;
1190 case BTNICON_GEAR:
1191 if(!(sz%2)) ++sz;
1192 aw = ah = w2 = h2 = sz;
1193 w2 = zc_max(1, w2/6);
1194 h2 = zc_max(1, h2/6);
1195 if(!(h2%2)) ++h2;
1196 if(!(w2%2)) ++w2;
1197 break;
1198 case BTNICON_TRASH:
1199 if(!(sz%2)) ++sz;
1200 aw = ah = w2 = h2 = sz;
1201 w2 = zc_max(1, w2/6);
1202 h2 = zc_max(1, h2/6);
1203 if(!(h2%2)) ++h2;
1204 if(!(w2%2)) ++w2;
1205 break;
1206 case BTNICON_MINUS:
1207 if(!(sz%2)) ++sz;
1208 aw = ah = w2 = h2 = sz;
1209 h2 /= 3;
1210 if(!(h2%2)) ++h2;
1211 break;
1212 }
1213 int woff = (aw/2)+1, hoff = (ah/2)+1;
1214 int cx = center ? (x-aw/2) : x,
1215 cy = center ? (y-ah/2) : y;
1216 switch(icon)
1217 {
1218 case BTNICON_ARROW_UP:
1219 draw_arrow(dest, col, x, cy, ah, true, center);
1220 break;
1221 case BTNICON_ARROW_DOWN:
1222 draw_arrow(dest, col, x, cy, ah, false, center);
1223 break;
1224 case BTNICON_ARROW_LEFT:
1225 draw_arrow_horz(dest, col, cx, y, aw, true, center);
1226 break;
1227 case BTNICON_ARROW_RIGHT:
1228 draw_arrow_horz(dest, col, cx, y, aw, false, center);
1229 break;
1230 case BTNICON_CONTRACT_VERT:
1231 draw_arrow(dest, col, x, cy-hoff, ah, false, center);
1232 draw_arrow(dest, col, x, cy+hoff, ah, true, center);
1233 break;
1234 case BTNICON_EXPAND_VERT:
1235 draw_arrow(dest, col, x, cy-hoff, ah, true, center);
1236 draw_arrow(dest, col, x, cy+hoff, ah, false, center);
1237 break;
1238 case BTNICON_CONTRACT_HORZ:
1239 draw_arrow_horz(dest, col, cx-woff, y, aw, false, center);
1240 draw_arrow_horz(dest, col, cx+woff, y, aw, true, center);
1241 break;
1242 case BTNICON_EXPAND_HORZ:
1243 draw_arrow_horz(dest, col, cx-woff, y, aw, true, center);
1244 draw_arrow_horz(dest, col, cx+woff, y, aw, false, center);
1245 break;
1246 case BTNICON_ARROW_LEFT2:
1247 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1248 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1249 break;
1250 case BTNICON_ARROW_LEFT3:
1251 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1252 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1253 draw_arrow_horz(dest, col, cx+w2*2, y, w2, true, center);
1254 break;
1255 case BTNICON_ARROW_RIGHT2:
1256 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1257 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1258 break;
1259 case BTNICON_ARROW_RIGHT3:
1260 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1261 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1262 draw_arrow_horz(dest, col, cx+w2*2, y, w2, false, center);
1263 break;
1264 case BTNICON_STOPSQUARE:
1265 rectfill(dest, cx, cy, cx+aw-1, cy+ah-1, col);
1266 break;
1267 case BTNICON_MINUS:
1268 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1269 break;
1270 case BTNICON_PLUS:
1271 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1272 rectfill(dest, cx+(aw/2)-(w2/2), cy, cx+(aw/2)+(w2/2), cy+ah-1, col);
1273 break;
1274 case BTNICON_GEAR:
1275 {
1276 BITMAP* tmp = create_bitmap_ex(8, sz, sz);
1277 int tx = cx, ty = cy;
1278 cx = cy = 0;
1279 clear_bitmap(tmp);
1280 rectfill(tmp, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1281 rectfill(tmp, cx+(aw/2)-(w2/2), cy, cx+(aw/2)+(w2/2), cy+ah-1, col);
1282 rotate_sprite(tmp, tmp, 0, 0, ftofix(DegtoFix(45.0)));
1283 circlefill(tmp, sz/2, sz/2, round((sz / 2) * 0.6), col);
1284 circlefill(tmp, sz/2, sz/2, round((sz / 2) * 0.3), 0);
1285 masked_blit(tmp, dest, 0, 0, tx-1, ty-1, sz, sz);
1286 destroy_bitmap(tmp);
1287 break;
1288 }
1289 case BTNICON_TRASH:
1290 {
1291 BITMAP* tmp = create_bitmap_ex(8, sz, sz);
1292 clear_bitmap(tmp);
1293 int tx = cx, ty = cy;
1294 cx = cy = 0;
1295 const int TOP_GAP = 2;
1296 const int TOP_BUMP_H = 4;
1297 const int TOP_BUMP_CUT_V = 2;
1298 int TOP_BUMP_CUT_H = w2;
1299 int INNER_VGAP = zc_max(1, h2/2);
1300 int VLINE_WIDTH = zc_max(1, w2/2);
1301 if (!(VLINE_WIDTH%2)) --VLINE_WIDTH;
1302 rectfill(tmp, cx + aw * 0.25_zf, cy, cx + aw * 0.75_zf, cy + TOP_BUMP_H, col);
1303 rectfill(tmp, cx + aw * 0.25_zf + TOP_BUMP_CUT_H, cy + TOP_BUMP_CUT_V, cx + aw * 0.75_zf - TOP_BUMP_CUT_H, cy + TOP_BUMP_H, 0);
1304 rectfill(tmp, cx, cy + (TOP_GAP + TOP_BUMP_H), cx+aw-1, cy+h2, col);
1305 int xs[] = {cx, cx+aw-1, cx+aw-1-w2, cx+w2};
1306 int ys[] = {cy+h2+TOP_GAP, cy+h2+TOP_GAP, cy+ah-1, cy+ah-1};
1307 triangle(tmp, xs[0], ys[0], xs[1], ys[1], xs[2], ys[2], col);
1308 triangle(tmp, xs[2], ys[2], xs[3], ys[3], xs[0], ys[0], col);
1309
1310 zfix tw = aw;
1311 zfix xls[] = {cx + tw * 0.25_zf + 1, cx + tw * 0.5_zf, cx + tw * 0.75_zf - 1};
1312 int ly = cy+h2+TOP_GAP+INNER_VGAP;
1313 int ly2 = cy+ah-1-INNER_VGAP;
1314 int yls[] = {ly2 - 2, ly2, ly2 - 2};
1315 for (int q = 0; q < 3; ++q)
1316 rectfill(tmp, xls[q] - VLINE_WIDTH / 2_zf, ly, xls[q] + VLINE_WIDTH / 2_zf, yls[q], 0);
1317
1318 masked_blit(tmp, dest, 0, 0, tx, ty, sz, sz);
1319 destroy_bitmap(tmp);
1320 break;
1321 }
1322 }
1323 }
1324 /* draw_graphics_button:
1325 * Helper for jwin_button_proc.
1326 */
1327 void jwin_draw_graphics_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, BITMAP *bmp, BITMAP *bmp2, int32_t flags, bool show_dotted_rect, bool overlay)
1328 {
1329 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1330
1331 if(flags & D_SELECTED)
1332 jwin_draw_button(dest, x, y, w, h, 2, 0);
1333 else if(!(flags & D_GOTFOCUS))
1334 jwin_draw_button(dest, x, y, w, h, 0, 0);
1335 else
1336 {
1337 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1338 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1339 }
1340
1341 if(!(flags & D_DISABLED))
1342 {
1343 // gui_textout_ex(dest, str, x+w/2+g, y+h/2-text_height(font)/2+g, scheme[jcBOXFG], -1, TRUE);
1344 if(bmp!=NULL)
1345 {
1346 if(overlay)
1347 {
1348 masked_blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1349 }
1350 else
1351 {
1352 blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1353 }
1354 }
1355 }
1356 else
1357 {
1358 // gui_textout_ex(dest, str, x+w/2+1,y+h/2-text_height(font)/2+1, scheme[jcLIGHT], -1, TRUE);
1359 // gui_textout_ex(dest, str, x+w/2, y+h/2-text_height(font)/2, scheme[jcMEDDARK], -1, TRUE);
1360 if(bmp2!=NULL)
1361 {
1362 if(overlay)
1363 {
1364 masked_blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1365 }
1366 else
1367 {
1368 blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1369 }
1370 }
1371 }
1372
1373 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1374 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1375 }
1376
1377 /* jwin_button_proc:
1378 * A button object (the dp field points to the text string). This object
1379 * can be selected by clicking on it with the mouse or by pressing its
1380 * keyboard shortcut. If the D_EXIT flag is set, selecting it will close
1381 * the dialog, otherwise it will toggle on and off.
1382 */
1383 int32_t jwin_button_proc(int32_t msg, DIALOG *d, int32_t)
1384 {
1385 int32_t down=0;
1386 int32_t selected=(d->flags&D_SELECTED)?1:0;
1387 int32_t disabled=(d->flags&D_DISABLED)?1:0;
1388 int32_t last_draw;
1389
1390 switch(msg)
1391 {
1392 case MSG_DRAW:
1393 {
1394 FONT *oldfont = font;
1395
1396 if(d->dp2)
1397 {
1398 font = (FONT*)d->dp2;
1399 }
1400
1401 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, (char*)d->dp, d->flags, true);
1402 font = oldfont;
1403 }
1404 break;
1405
1406 case MSG_WANTFOCUS:
1407 return D_WANTFOCUS;
1408
1409 case MSG_KEY:
1410 if(disabled) break;
1411 /* close dialog? */
1412 if(d->flags & D_EXIT)
1413 {
1414 return D_CLOSE;
1415 }
1416 if(d->d2 == 1) //Insta-button
1417 {
1418 GUI_EVENT(d, geCLICK);
1419 break;
1420 }
1421 /* or just toggle */
1422 d->flags ^= D_SELECTED;
1423 GUI_EVENT(d, geCLICK);
1424 object_message(d, MSG_DRAW, 0);
1425 break;
1426
1427 case MSG_CLICK:
1428 {
1429 if(disabled) break;
1430 if(d->d2 == 1) //Insta-button
1431 {
1432 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1433 {
1434 GUI_EVENT(d, geCLICK);
1435 if(d->flags & D_EXIT)
1436 return D_CLOSE;
1437 }
1438 }
1439 else
1440 {
1441 last_draw = 0;
1442
1443 /* track the mouse until it is released */
1444 while(gui_mouse_b())
1445 {
1446 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1447
1448 /* redraw? */
1449 bool should_redraw = false;
1450 if(last_draw != down)
1451 {
1452 if(down != selected)
1453 d->flags |= D_SELECTED;
1454 else
1455 d->flags &= ~D_SELECTED;
1456
1457 object_message(d, MSG_DRAW, 0);
1458 last_draw = down;
1459 should_redraw = true;
1460 }
1461
1462 /* let other objects continue to animate */
1463 int r = broadcast_dialog_message(MSG_IDLE, 0);
1464 if (r & D_REDRAWME) should_redraw = true;
1465
1466 if (should_redraw)
1467 {
1468 update_hw_screen();
1469 }
1470 }
1471
1472 /* redraw in normal state */
1473 if(down)
1474 {
1475 GUI_EVENT(d, geCLICK);
1476 if(d->flags&D_EXIT)
1477 {
1478 d->flags &= ~D_SELECTED;
1479 object_message(d, MSG_DRAW, 0);
1480 }
1481 }
1482
1483 /* should we close the dialog? */
1484 if(down && (d->flags & D_EXIT))
1485 return D_CLOSE;
1486 }
1487 }
1488 break;
1489 }
1490 return D_O_K;
1491 }
1492 int32_t jwin_iconbutton_proc(int32_t msg, DIALOG *d, int32_t)
1493 {
1494 int32_t down=0;
1495 int32_t selected=(d->flags&D_SELECTED)?1:0;
1496 int32_t last_draw;
1497
1498 switch(msg)
1499 {
1500 case MSG_DRAW:
1501 {
1502 jwin_draw_icon_button(screen, d->x, d->y, d->w, d->h, d->d1, d->flags, true);
1503 }
1504 break;
1505
1506 case MSG_WANTFOCUS:
1507 return D_WANTFOCUS;
1508
1509 case MSG_KEY:
1510 /* close dialog? */
1511 if(d->flags & D_EXIT)
1512 {
1513 return D_CLOSE;
1514 }
1515 if(d->d2 == 1) //Insta-button
1516 {
1517 GUI_EVENT(d, geCLICK);
1518 break;
1519 }
1520 /* or just toggle */
1521 d->flags ^= D_SELECTED;
1522 GUI_EVENT(d, geCLICK);
1523 object_message(d, MSG_DRAW, 0);
1524 break;
1525
1526 case MSG_CLICK:
1527 {
1528 if(d->d2 == 1) //Insta-button
1529 {
1530 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1531 {
1532 GUI_EVENT(d, geCLICK);
1533 if(d->flags & D_EXIT)
1534 return D_CLOSE;
1535 }
1536 }
1537 else
1538 {
1539 last_draw = 0;
1540
1541 /* track the mouse until it is released */
1542 while(gui_mouse_b())
1543 {
1544 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1545
1546 /* redraw? */
1547 bool should_redraw = false;
1548 if(last_draw != down)
1549 {
1550 if(down != selected)
1551 d->flags |= D_SELECTED;
1552 else
1553 d->flags &= ~D_SELECTED;
1554
1555 object_message(d, MSG_DRAW, 0);
1556 last_draw = down;
1557 should_redraw = true;
1558 }
1559
1560 /* let other objects continue to animate */
1561 int r = broadcast_dialog_message(MSG_IDLE, 0);
1562 if (r & D_REDRAWME) should_redraw = true;
1563
1564 if (should_redraw)
1565 {
1566 update_hw_screen();
1567 }
1568 }
1569
1570 /* redraw in normal state */
1571 if(down)
1572 {
1573 GUI_EVENT(d, geCLICK);
1574 if(d->flags&D_EXIT)
1575 {
1576 d->flags &= ~D_SELECTED;
1577 object_message(d, MSG_DRAW, 0);
1578 }
1579 }
1580
1581 /* should we close the dialog? */
1582 if(down && (d->flags & D_EXIT))
1583 return D_CLOSE;
1584 }
1585 }
1586 break;
1587 }
1588 return D_O_K;
1589 }
1590 int32_t jwin_infobtn_proc(int32_t msg, DIALOG *d, int32_t)
1591 {
1592 int32_t down=0;
1593 int32_t selected=(d->flags&D_SELECTED)?1:0;
1594 int32_t last_draw;
1595 std::string* str = (std::string*)d->dp;
1596 bool dis = (d->flags & D_DISABLED) || !str || !((*str)[0]) || str->find_first_not_of(" \t")==std::string::npos;
1597 int flags = d->flags | (dis?D_DISABLED:0);
1598 bool show = false;
1599 switch(msg)
1600 {
1601 case MSG_DRAW:
1602 {
1603 FONT *oldfont = font;
1604
1605 if(d->dp2)
1606 font = (FONT*)d->dp2;
1607
1608 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, "?", flags, true);
1609 font = oldfont;
1610 }
1611 break;
1612
1613 case MSG_WANTFOCUS:
1614 if(dis) break;
1615 return D_WANTFOCUS;
1616
1617 case MSG_KEY:
1618 if(dis) break;
1619 show = true;
1620 break;
1621
1622 case MSG_CLICK:
1623 {
1624 if(dis) break;
1625 if(d->d2 == 1) //Insta-button
1626 {
1627 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1628 {
1629 show = true;
1630 break;
1631 }
1632 }
1633 else
1634 {
1635 last_draw = 0;
1636
1637 /* track the mouse until it is released */
1638 while(gui_mouse_b())
1639 {
1640 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1641
1642 /* redraw? */
1643 bool should_redraw = false;
1644 if(last_draw != down)
1645 {
1646 if(down != selected)
1647 d->flags |= D_SELECTED;
1648 else
1649 d->flags &= ~D_SELECTED;
1650
1651 object_message(d, MSG_DRAW, 0);
1652 last_draw = down;
1653 should_redraw = true;
1654 }
1655
1656 /* let other objects continue to animate */
1657 int r = broadcast_dialog_message(MSG_IDLE, 0);
1658 if (r & D_REDRAWME) should_redraw = true;
1659
1660 if (should_redraw)
1661 {
1662 update_hw_screen();
1663 }
1664 }
1665
1666 /* redraw in normal state */
1667 if(down)
1668 show = true;
1669 }
1670 }
1671 break;
1672 }
1673 if(show)
1674 {
1675 d->flags &= ~D_SELECTED;
1676 object_message(d, MSG_DRAW, 0);
1677 InfoDialog("Info",*str).show();
1678 GUI_EVENT(d, geCLICK);
1679 }
1680 return D_O_K;
1681 }
1682
1683 /* jwin_func_button_proc:
1684 * A button that runs a void() function when clicked.
1685 * dp: Button text
1686 * dp2: Function to run
1687 */
1688 int32_t jwin_func_button_proc(int32_t msg, DIALOG *d, int32_t c)
1689 {
1690 int32_t down=0;
1691 int32_t selected=(d->flags&D_SELECTED)?1:0;
1692 int32_t last_draw;
1693
1694 if(msg==MSG_CLICK || msg==MSG_KEY)
1695 {
1696 last_draw = 0;
1697
1698 /* track the mouse until it is released */
1699 while(gui_mouse_b())
1700 {
1701 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1702
1703 /* redraw? */
1704 bool should_redraw = false;
1705 if(last_draw != down)
1706 {
1707 if(down != selected)
1708 d->flags |= D_SELECTED;
1709 else
1710 d->flags &= ~D_SELECTED;
1711
1712 object_message(d, MSG_DRAW, 0);
1713 last_draw = down;
1714 should_redraw = true;
1715 }
1716
1717 /* let other objects continue to animate */
1718 int r = broadcast_dialog_message(MSG_IDLE, 0);
1719 if (r & D_REDRAWME) should_redraw = true;
1720
1721 if (should_redraw)
1722 {
1723 update_hw_screen();
1724 }
1725 }
1726
1727 /* redraw in normal state */
1728 if(down)
1729 {
1730 if(d->flags&D_EXIT)
1731 {
1732 d->flags &= ~D_SELECTED;
1733 object_message(d, MSG_DRAW, 0);
1734 }
1735 }
1736
1737 /* pop up and call the function */
1738 if(down)
1739 {
1740 d->flags &= ~D_SELECTED;
1741 object_message(d, MSG_DRAW, 0);
1742 typedef void (*funcType)(void);
1743 funcType func=reinterpret_cast<funcType>(d->dp3);
1744 func();
1745 }
1746
1747 return D_O_K;
1748 }
1749
1750 return jwin_button_proc(msg, d, c);
1751 }
1752
1753 /*(int32_t x = atoi(d->dp);
1754 if ( x > 256 )
1755 d->dp = (char*)"255";
1756 elseif (x < 0 ) d->dp = (char*)"0";
1757 */
1758
1759 #ifdef ALLEGRO_MACOSX
1760 static int WORD_FLAG = KB_ALT_FLAG;
1761 static int LINE_FLAG = KB_COMMAND_FLAG;
1762 #else
1763 static int WORD_FLAG = KB_CTRL_FLAG;
1764 static int LINE_FLAG = KB_ALT_FLAG;
1765 #endif
1766
1767 static int classify_char(char c)
1768 {
1769 if (c == ' ' || c == '\t' || c == '\r')
1770 return 0;
1771 if (c == '/' || c == '\\')
1772 return 1;
1773 return 2;
1774 }
1775
1776 static void delete_word(char* s, int* cursor)
1777 {
1778 int start = *cursor;
1779 if (start == 0) return;
1780
1781 int i = start - 1;
1782 int first_ch_class = classify_char(s[i]);
1783 while (i >= 0 && s[i])
1784 {
1785 if (classify_char(s[i]) != first_ch_class)
1786 break;
1787 i--;
1788 }
1789
1790 i++;
1791 *cursor = i;
1792
1793 int j = start;
1794 while (s[j])
1795 s[i++] = s[j++];
1796 s[i] = 0;
1797 }
1798
1799 static void delete_line(char* s, int* cursor)
1800 {
1801 int start = *cursor;
1802 if (start == 0) return;
1803
1804 int i = start - 1;
1805 while (i >= 0 && s[i])
1806 {
1807 bool is_newline = s[i] == '\n';
1808 if (is_newline) break;
1809 i--;
1810 }
1811
1812 i++;
1813 *cursor = i;
1814
1815 int j = start;
1816 while (s[j])
1817 s[i++] = s[j++];
1818 s[i] = 0;
1819 }
1820
1821 int32_t jwin_vedit_proc(int32_t msg, DIALOG *d, int32_t c)
1822 {
1823 if(d->flags & D_HIDDEN)
1824 {
1825 switch(msg)
1826 {
1827 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
1828 return D_O_K;
1829 }
1830 }
1831 if(d->h < 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
1832 return jwin_edit_proc(msg, d, c);
1833 static char nullbuf[2];
1834 sprintf(nullbuf, " ");
1835 int32_t f, l, p, w, x, y, fg, bg;
1836 int32_t lastSpace = -1;
1837 char *s;
1838 char buf[2] = {0,0};
1839
1840 if(d->dp==NULL)
1841 {
1842 d->dp=(void *)nullbuf;
1843 }
1844
1845 s = (char*)d->dp;
1846 l = (int32_t)strlen(s);
1847
1848 int32_t cursor_start = d->d2 & 0x0000FFFF;
1849 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
1850 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
1851 if (cursor_start == 0xFFFF)
1852 cursor_start = -1;
1853 if (cursor_end == 0xFFFF)
1854 cursor_end = -1;
1855
1856 if(cursor_start > l)
1857 cursor_start = l;
1858 if(cursor_end > l)
1859 cursor_end = l;
1860 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
1861 auto high_cursor = zc_max(cursor_start,cursor_end);
1862 bool range_selected = cursor_end > -1;
1863
1864 FONT *oldfont = font;
1865 if(d->dp2)
1866 font = (FONT*)d->dp2;
1867
1868 auto* char_length = font->vtable->char_length;
1869 std::vector<size_t> lines;
1870 x = 0;
1871
1872 y = d->y + 2;
1873 size_t ind = 0;
1874 int32_t yinc = text_height(font)+2;
1875 int32_t maxy = y;
1876 size_t maxlines = 1;
1877 while(maxy+yinc < d->y+d->h-3)
1878 {
1879 maxy += yinc;
1880 ++maxlines;
1881 }
1882 size_t half_width = (maxlines-1)/2;
1883 size_t line_scroll = 0;
1884 size_t focused_line = size_t(-1);
1885 size_t focused_line2 = size_t(-1);
1886 switch(msg)
1887 {
1888 //Only these messages need these calculations, so save processing.
1889 case MSG_DRAW:
1890 case MSG_CLICK:
1891 case MSG_CHAR:
1892 {
1893 for(auto q = 0; q <= l; ++q)
1894 {
1895 char c = s[q] ? s[q] : ' ';
1896 x += char_length(font, c);
1897 if(x > d->w - 6)
1898 {
1899 // Line's too long, break
1900 if(lastSpace >= 0)
1901 {
1902 q = lastSpace+1;
1903 lines.push_back(q);
1904 lastSpace = -1;
1905 }
1906 else
1907 {
1908 lines.push_back(q);
1909 }
1910 x = 0;
1911 --q; //counteract increment
1912 }
1913 else if(c == ' ')
1914 lastSpace = q;
1915 }
1916 if(lines.empty() || lines.back() != l+1)
1917 lines.push_back(l+1);
1918 for(size_t line = 0; line < lines.size(); ++line)
1919 {
1920 if(size_t(range_selected ? cursor_end : cursor_start) < lines[line]) //should ALWAYS execute once
1921 {
1922 focused_line = line;
1923 break;
1924 }
1925 }
1926 if(!range_selected)
1927 {
1928 focused_line2 = -1;
1929 }
1930 else for(size_t line = 0; line < lines.size(); ++line)
1931 {
1932 if(size_t(cursor_start) < lines[line]) //should ALWAYS execute once
1933 {
1934 focused_line2 = line;
1935 break;
1936 }
1937 }
1938 if (focused_line >= lines.size())
1939 focused_line = lines.size() - 1;
1940 if (focused_line2 >= lines.size())
1941 focused_line2 = lines.size() - 1;
1942 if(maxlines >= lines.size() || focused_line <= half_width)
1943 line_scroll = 0;
1944 else if(lines.size()-maxlines+half_width < focused_line)
1945 line_scroll = lines.size()-maxlines+half_width-1;
1946 else
1947 line_scroll = focused_line - half_width;
1948 }
1949 }
1950 font = oldfont; //in case of early return, need to reset here
1951 static bool dclick = false;
1952 switch(msg)
1953 {
1954 case MSG_START:
1955 dclick = false;
1956 cursor_start = (int32_t)strlen((char*)d->dp);
1957 cursor_end = -1;
1958 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1959 break;
1960
1961 case MSG_DRAW:
1962 {
1963 if(d->dp2)
1964 font = (FONT*)d->dp2;
1965 if(d->flags & D_DISABLED)
1966 {
1967 fg = scheme[jcDISABLED_FG];
1968 bg = scheme[jcDISABLED_BG];
1969 }
1970 else if(d->flags & D_READONLY)
1971 {
1972 fg = scheme[jcALT_TEXTFG];
1973 bg = scheme[jcALT_TEXTBG];
1974 }
1975 else
1976 {
1977 fg = scheme[jcTEXTFG];
1978 bg = scheme[jcTEXTBG];
1979 }
1980
1981 //Fill the BG
1982 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg);
1983
1984 //Now the text
1985 size_t m = zc_min(line_scroll + maxlines, lines.size());
1986 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
1987 for(size_t line = line_scroll; line < m; ++line, y+=yinc)
1988 {
1989 x = 3;
1990 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1991 {
1992 char c = s[ind] ? s[ind] : ' ';
1993 w = char_length(font, c);
1994 bool focused = range_selected
1995 ? (ind >= low_cursor && ind <= high_cursor)
1996 : (ind == cursor_start);
1997 f = (focused && (d->flags & D_GOTFOCUS));
1998 buf[0] = c;
1999 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
2000 x += w;
2001 }
2002 }
2003
2004 font = oldfont;
2005 break;
2006 }
2007
2008 case MSG_DCLICK:
2009 if ((gui_mouse_b() & 2) != 0)
2010 break;
2011 if (d->flags & (D_DISABLED | D_READONLY))
2012 break;
2013 dclick = true;
2014 break;
2015 case MSG_CLICK:
2016 {
2017 int oldcursor = d->d2;
2018
2019 if(d->flags & (D_DISABLED|D_READONLY))
2020 break;
2021 if(d->dp2)
2022 font = (FONT*)d->dp2;
2023
2024 bool found = false;
2025 for(size_t line = line_scroll; line < lines.size() && line < (line_scroll + maxlines); ++line, y+=yinc)
2026 {
2027 if(gui_mouse_y() >= y+yinc)
2028 continue;
2029 x = d->x+3;
2030 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2031 {
2032 x += char_length(font, s[ind]);
2033 if(x >= gui_mouse_x())
2034 {
2035 if(key_shifts&KB_SHIFT_FLAG)
2036 cursor_end = ind;
2037 else
2038 {
2039 cursor_start = ind;
2040 cursor_end = -1;
2041 if (dclick)
2042 cursor_end = cursor_start;
2043 }
2044 found = true;
2045 break;
2046 }
2047 }
2048 break;
2049 }
2050 if(!found)
2051 {
2052 if(key_shifts&KB_SHIFT_FLAG)
2053 cursor_end = l;
2054 else
2055 {
2056 cursor_start = l;
2057 cursor_end = -1;
2058 if (dclick)
2059 cursor_end = cursor_start;
2060 }
2061 }
2062
2063 if (dclick)
2064 {
2065 while (cursor_start > 0 && cursor_start < l)
2066 {
2067 if (s[cursor_start] == ' ')
2068 {
2069 if (cursor_start <= cursor_end)
2070 ++cursor_start;
2071 else
2072 --cursor_start;
2073 break;
2074 }
2075 // Select the entire SCC text (as long as user double clicks on the name part).
2076 if (s[cursor_start] == '\\' && (cursor_start > 0 && !isdigit(s[cursor_start - 1])))
2077 break;
2078 if (cursor_start <= cursor_end)
2079 --cursor_start;
2080 else
2081 ++cursor_start;
2082 }
2083 while (cursor_end > 0 && cursor_end < l)
2084 {
2085 if (s[cursor_end] == ' ')
2086 {
2087 if (cursor_end >= cursor_start)
2088 --cursor_end;
2089 else
2090 ++cursor_end;
2091 break;
2092 }
2093 // Select the entire SCC text (as long as user double clicks on the name part).
2094 if (s[cursor_end] == '\\' && (cursor_end == l - 1 || s[cursor_end + 1] == ' '))
2095 break;
2096 if (cursor_end >= cursor_start)
2097 ++cursor_end;
2098 else
2099 --cursor_end;
2100 }
2101 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2102 d->flags |= D_DIRTY;
2103 }
2104 else
2105 {
2106 if (cursor_end == cursor_start) cursor_end = -1;
2107 else d->flags |= D_DIRTY;
2108 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2109 }
2110
2111 object_message(d, MSG_DRAW, 0);
2112 font = oldfont;
2113 dclick = false;
2114 if (oldcursor != d->d2)
2115 GUI_EVENT(d, geCHANGE_CURSOR);
2116 break;
2117 }
2118
2119 case MSG_WANTFOCUS:
2120 case MSG_LOSTFOCUS:
2121 case MSG_KEY:
2122 if(d->flags & (D_DISABLED|D_READONLY))
2123 break;
2124 return D_WANTFOCUS;
2125
2126 case MSG_CHAR:
2127 {
2128 if(d->flags & (D_DISABLED|D_READONLY))
2129 break;
2130 bool shifted = key_shifts & KB_SHIFT_FLAG;
2131 bool ctrl = key_shifts & KB_CTRL_CMD_FLAG;
2132 bool word_modifier = key_shifts & WORD_FLAG;
2133 bool line_modifier = key_shifts & LINE_FLAG;
2134 bool change_cursor = true;
2135 int32_t scursor = cursor_start, ecursor = cursor_end;
2136 char upper_c = c>>8;
2137 char lower_c = c&255;
2138
2139 if(shifted)
2140 {
2141 if(ecursor < 0)
2142 {
2143 ecursor = scursor;
2144 focused_line2 = focused_line;
2145 }
2146 }
2147 if(upper_c == KEY_LEFT)
2148 {
2149 if(shifted)
2150 {
2151 if(ecursor>0)
2152 --ecursor;
2153 }
2154 else
2155 {
2156 ecursor = -1;
2157 if(scursor > 0)
2158 --scursor;
2159 }
2160 }
2161 else if(upper_c == KEY_RIGHT)
2162 {
2163 if(shifted)
2164 {
2165 if(ecursor < l)
2166 ++ecursor;
2167 }
2168 else
2169 {
2170 ecursor = -1;
2171 if(scursor < l)
2172 ++scursor;
2173 }
2174 }
2175 else if(upper_c == KEY_UP || upper_c == KEY_DOWN)
2176 {
2177 if(shifted)
2178 {
2179 size_t line = focused_line2 + (upper_c == KEY_UP ? -1 : 1);
2180 if(!focused_line2 && upper_c == KEY_UP)
2181 ecursor = 0;
2182 else if(line >= lines.size())
2183 ecursor = l;
2184 else
2185 {
2186 if(d->dp2)
2187 font = (FONT*)d->dp2;
2188 x = d->x + 3;
2189 for(ind = focused_line2 ? lines[focused_line2-1] : 0; ind < lines[focused_line2]; ++ind)
2190 {
2191 w = char_length(font, s[ind]);
2192 if(ind < size_t(ecursor))
2193 x += w;
2194 else
2195 {
2196 x += w / 2;
2197 break;
2198 }
2199 }
2200
2201 int32_t tx = d->x+3;
2202 bool done = false;
2203 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2204 {
2205 tx += char_length(font, s[ind] ? s[ind] : ' ');
2206 if(tx < x)
2207 continue;
2208 ecursor = ind;
2209 done = true;
2210 break;
2211 }
2212 font = oldfont;
2213 if(!done)
2214 {
2215 ecursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2216 }
2217 }
2218 }
2219 else
2220 {
2221 ecursor = -1;
2222 if(range_selected)
2223 {
2224 focused_line = focused_line2;
2225 scursor = ecursor;
2226 }
2227 size_t line = focused_line + (upper_c == KEY_UP ? -1 : 1);
2228 if(!focused_line && upper_c == KEY_UP)
2229 scursor = 0;
2230 else if(line >= lines.size())
2231 scursor = l;
2232 else
2233 {
2234 if(d->dp2)
2235 font = (FONT*)d->dp2;
2236 x = d->x + 3;
2237 for(ind = focused_line ? lines[focused_line-1] : 0; ind < lines[focused_line]; ++ind)
2238 {
2239 w = char_length(font, s[ind]);
2240 if(ind < size_t(scursor))
2241 x += w;
2242 else
2243 {
2244 x += w / 2;
2245 break;
2246 }
2247 }
2248
2249 int32_t tx = d->x+3;
2250 bool done = false;
2251 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2252 {
2253 tx += char_length(font, s[ind] ? s[ind] : ' ');
2254 if(tx < x)
2255 continue;
2256 scursor = ind;
2257 done = true;
2258 break;
2259 }
2260 font = oldfont;
2261 if(!done)
2262 {
2263 scursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2264 }
2265 }
2266 }
2267 }
2268 else if(upper_c == KEY_HOME)
2269 {
2270 if(shifted)
2271 ecursor = 0;
2272 else
2273 {
2274 ecursor = -1;
2275 scursor = 0;
2276 }
2277 }
2278 else if(upper_c == KEY_END)
2279 {
2280 if(shifted)
2281 ecursor = l;
2282 else
2283 {
2284 ecursor = -1;
2285 scursor = l;
2286 }
2287 }
2288 else if(upper_c == KEY_DEL)
2289 {
2290 if(ctrl)
2291 {
2292 s[0] = 0;
2293 scursor = 0;
2294 ecursor = -1;
2295 GUI_EVENT(d, geCHANGE_VALUE);
2296 }
2297 else if(range_selected)
2298 {
2299 ecursor = -1;
2300 scursor = low_cursor;
2301 size_t ind = low_cursor, ind2 = high_cursor+1;
2302 while(ind2 < l && s[ind2])
2303 s[ind++] = s[ind2++];
2304 while(s[ind])
2305 s[ind++] = 0;
2306 GUI_EVENT(d, geCHANGE_VALUE);
2307 }
2308 else if(scursor < l)
2309 {
2310 for(p=scursor; s[p]; p++)
2311 s[p] = s[p+1];
2312 GUI_EVENT(d, geCHANGE_VALUE);
2313 }
2314 }
2315 else if(upper_c == KEY_BACKSPACE)
2316 {
2317 if(line_modifier)
2318 {
2319 delete_line(s, &scursor);
2320 ecursor = -1;
2321 GUI_EVENT(d, geCHANGE_VALUE);
2322 }
2323 else if(word_modifier)
2324 {
2325 delete_word(s, &scursor);
2326 ecursor = -1;
2327 GUI_EVENT(d, geCHANGE_VALUE);
2328 }
2329 else if(range_selected)
2330 {
2331 ecursor = -1;
2332 scursor = low_cursor;
2333 size_t ind = low_cursor, ind2 = high_cursor+1;
2334 while(ind2 < l && s[ind2])
2335 s[ind++] = s[ind2++];
2336 while(s[ind])
2337 s[ind++] = 0;
2338 GUI_EVENT(d, geCHANGE_VALUE);
2339 }
2340 else if(scursor > 0)
2341 {
2342 --scursor;
2343 for(p=scursor; s[p]; p++)
2344 s[p] = s[p+1];
2345 GUI_EVENT(d, geCHANGE_VALUE);
2346 }
2347 }
2348 else if(upper_c == KEY_ENTER)
2349 {
2350 change_cursor = false;
2351 GUI_EVENT(d, geENTER);
2352 if(d->flags & D_EXIT)
2353 {
2354 object_message(d, MSG_DRAW, 0);
2355 return D_CLOSE;
2356 }
2357 else
2358 return D_O_K;
2359 }
2360 else if(upper_c == KEY_TAB)
2361 {
2362 change_cursor = false;
2363 return D_O_K;
2364 }
2365 else if(ctrl && upper_c == KEY_C)
2366 {
2367 change_cursor = false;
2368 std::ostringstream oss;
2369 if(range_selected)
2370 {
2371 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2372 {
2373 if(s[ind])
2374 oss << s[ind];
2375 }
2376 }
2377 else
2378 {
2379 if(s[scursor])
2380 oss << s[scursor];
2381 }
2382 set_al_clipboard(oss.str());
2383 }
2384 else if (ctrl && upper_c == KEY_V && clipboard_has_text())
2385 {
2386 std::string cb;
2387 if(get_al_clipboard(cb))
2388 {
2389 int ind = low_cursor, ind2 = high_cursor + 1;
2390 if (range_selected)
2391 {
2392 //Delete selected text
2393 ecursor = -1;
2394 scursor = low_cursor;
2395 while (s[ind2] && ind2 < l)
2396 s[ind++] = s[ind2++];
2397 while (s[ind])
2398 s[ind++] = 0;
2399 l = (int32_t)strlen(s);
2400 }
2401 //Move the text out of the way of the pasting
2402 int paste_len = cb.size();
2403 int paste_start = scursor;
2404 int paste_end = paste_start+paste_len;
2405 ind = strlen(s);
2406 ind2 = ind+paste_len;
2407 while(ind2 > d->d1)
2408 {
2409 --ind;
2410 --ind2;
2411 }
2412 size_t new_l = ind2;
2413 while(ind >= paste_start)
2414 {
2415 if(s[ind] || (ind&&s[ind-1]))
2416 {
2417 s[ind2] = s[ind];
2418 }
2419 --ind2; --ind;
2420 }
2421 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2422 {
2423 s[paste_start+q] = cb.at(q);
2424 }
2425 s[new_l] = 0;
2426 scursor = paste_start + paste_len;
2427 ecursor = -1;
2428 GUI_EVENT(d, geCHANGE_VALUE);
2429 }
2430 }
2431 else if (ctrl && upper_c == KEY_A)
2432 {
2433 cursor_start = 0;
2434 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2435 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2436 d->flags |= D_DIRTY;
2437 GUI_EVENT(d, geCHANGE_CURSOR);
2438 break;
2439 }
2440 else if(lower_c >= 32 && !ctrl)
2441 {
2442 if(range_selected)
2443 {
2444 //Delete selected text
2445 ecursor = -1;
2446 scursor = low_cursor;
2447 size_t ind = low_cursor, ind2 = high_cursor+1;
2448 while(ind2 < l && s[ind2])
2449 s[ind++] = s[ind2++];
2450 while(s[ind])
2451 s[ind++] = 0;
2452 l = (int32_t)strlen(s);
2453 //Type the character in its' place
2454 //(fallthrough)
2455 }
2456 if(l < d->d1)
2457 {
2458 ecursor = -1;
2459 s[l+1] = 0;
2460 size_t ind = l;
2461 while(ind >= scursor)
2462 {
2463 s[ind+1] = s[ind];
2464 if (!ind) break;
2465 --ind;
2466 }
2467
2468 s[scursor++] = lower_c;
2469
2470 GUI_EVENT(d, geCHANGE_VALUE);
2471 }
2472 }
2473 else
2474 return D_O_K;
2475
2476 if(change_cursor)
2477 {
2478 if (cursor_start != scursor)
2479 d->flags |= D_DIRTY;
2480
2481 cursor_end = ecursor; cursor_start = scursor;
2482 if (cursor_end == cursor_start) cursor_end = -1;
2483 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2484
2485 GUI_EVENT(d, geCHANGE_CURSOR);
2486 }
2487
2488 /* if we changed something, better redraw... */
2489 object_message(d, MSG_DRAW, 0);
2490 return D_USED_CHAR;
2491 }
2492 }
2493
2494 return D_O_K;
2495 }
2496
2497 /* jwin_edit_proc:
2498 * An editable text object (the dp field points to the string). When it
2499 * has the input focus (obtained by clicking on it with the mouse), text
2500 * can be typed into this object. The d1 field specifies the maximum
2501 * number of characters that it will accept, and d2 is the text cursor
2502 * position within the string.
2503 */
2504 int32_t jwin_edit_proc(int32_t msg, DIALOG *d, int32_t c)
2505 {
2506 if(d->flags & D_HIDDEN)
2507 {
2508 switch(msg)
2509 {
2510 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
2511 return D_O_K;
2512 }
2513 }
2514 if(d->h >= 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
2515 return jwin_vedit_proc(msg, d, c);
2516 int32_t f, l, p, w, x, y, fg, bg, fg2 = -1, bg2 = -1, fg3, bg3;
2517 int32_t b;
2518 int32_t scroll;
2519 char *s;
2520 char buf[2];
2521 static char nullbuf[2];
2522 sprintf(nullbuf, " ");
2523
2524 if(d->dp==NULL)
2525 {
2526 d->dp=(void *)nullbuf;
2527 }
2528
2529 s = (char*)d->dp;
2530 l = (int32_t)strlen(s);
2531
2532 int32_t cursor_start = d->d2 & 0x0000FFFF;
2533 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
2534 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
2535 if (cursor_start == 0xFFFF)
2536 cursor_start = -1;
2537 if (cursor_end == 0xFFFF)
2538 cursor_end = -1;
2539
2540 if(cursor_start > l)
2541 cursor_start = l;
2542 if(cursor_end > l)
2543 cursor_end = l;
2544 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
2545 auto high_cursor = zc_max(cursor_start,cursor_end);
2546
2547 /* calculate maximal number of displayable characters */
2548 b = x = 0;
2549
2550 if(cursor_start == l)
2551 {
2552 buf[0] = ' ';
2553 buf[1] = 0;
2554
2555 if(d->dp2)
2556 x = text_length((FONT*)d->dp2, buf);
2557 else
2558 x = text_length(font, buf);
2559 }
2560
2561 buf[1] = 0;
2562
2563 for(p=cursor_start; p>=0; p--)
2564 {
2565 buf[0] = s[p];
2566 b++;
2567
2568 if(d->dp2)
2569 x += text_length((FONT*)d->dp2, buf);
2570 else
2571 x += text_length(font, buf);
2572
2573 if(x > d->w-6)
2574 break;
2575 }
2576
2577 if(x <= d->w-6)
2578 {
2579 b = l;
2580 scroll = FALSE;
2581 }
2582 else
2583 {
2584 b--;
2585 scroll = TRUE;
2586 }
2587
2588 FONT *oldfont = font;
2589 static bool dclick = false;
2590 switch(msg)
2591 {
2592 case MSG_START:
2593 dclick = false;
2594 cursor_start = (int32_t)strlen((char*)d->dp);
2595 cursor_end = -1;
2596 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2597 break;
2598
2599 case MSG_DRAW:
2600 {
2601 if(d->dp2)
2602 {
2603 font = (FONT*)d->dp2;
2604 }
2605 if(d->flags & D_DISABLED)
2606 {
2607 fg2 = scheme[jcLIGHT];
2608 bg2 = scheme[jcDISABLED_BG];
2609 fg = scheme[jcDISABLED_FG];
2610 bg = -1;
2611 fg3 = fg;
2612 bg3 = bg2;
2613 }
2614 else if(d->flags & D_READONLY)
2615 {
2616 fg = scheme[jcALT_TEXTFG];
2617 bg = scheme[jcALT_TEXTBG];
2618 fg3 = fg;
2619 bg3 = bg;
2620 }
2621 else
2622 {
2623 fg = scheme[jcTEXTFG];
2624 bg = scheme[jcTEXTBG];
2625 fg3 = fg;
2626 bg3 = bg;
2627 }
2628
2629 x = 3;
2630 y = (d->h - text_height(font)) / 2 + d->y;
2631
2632 /* first fill in the edges */
2633
2634 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg3);
2635
2636 vline(screen, d->x+2, d->y+2, d->y+d->h-3, bg3);
2637
2638 /* now the text */
2639
2640 if(scroll)
2641 {
2642 p = cursor_start-b+1;
2643 b = cursor_start;
2644 }
2645 else
2646 p = 0;
2647 for(; p<=b; p++)
2648 {
2649 buf[0] = s[p] ? s[p] : ' ';
2650 w = text_length(font, buf);
2651
2652 if(x+w > d->w)
2653 break;
2654 bool focused = (cursor_end>-1)
2655 ? (p >= low_cursor && p <= high_cursor)
2656 : (p == cursor_start);
2657 f = fg2 < 0 && (focused && (d->flags & D_GOTFOCUS));
2658 if(fg2 > -1)
2659 {
2660 textout_ex(screen, font, buf, d->x+x+1, y+1, fg2, bg2);
2661 }
2662 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
2663 x += w;
2664 }
2665
2666 if(x < d->w-2)
2667 rectfill(screen, d->x+x, y, d->x+d->w-3, y+text_height(font)-1, bg3);
2668
2669 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
2670 font = oldfont;
2671 break;
2672 }
2673
2674 case MSG_DCLICK:
2675 if ((gui_mouse_b() & 2) != 0)
2676 break;
2677 if (d->flags & (D_DISABLED | D_READONLY))
2678 break;
2679 dclick = true;
2680 break;
2681 case MSG_CLICK:
2682 {
2683 if(d->flags & (D_DISABLED|D_READONLY))
2684 break;
2685 x = d->x+3;
2686
2687 if(scroll)
2688 {
2689 p = cursor_start-b+1;
2690 b = cursor_start;
2691 }
2692 else
2693 p = 0;
2694
2695 for(; p<b; p++)
2696 {
2697 buf[0] = s[p];
2698 x += text_length((d->dp2) ? (FONT*)d->dp2 : font, buf);
2699
2700 if(x > gui_mouse_x())
2701 break;
2702 }
2703
2704 if(key_shifts&KB_SHIFT_FLAG)
2705 cursor_end = MID(0, p, l);
2706 else
2707 {
2708 cursor_end = -1;
2709 cursor_start = MID(0, p, l);
2710 if (dclick)
2711 cursor_end = cursor_start;
2712 }
2713
2714 if (dclick)
2715 {
2716 while (cursor_start > 0 && cursor_start < l)
2717 {
2718 if (s[cursor_start] == ' ')
2719 {
2720 if (cursor_start <= cursor_end)
2721 ++cursor_start;
2722 else
2723 --cursor_start;
2724 break;
2725 }
2726 if (cursor_start <= cursor_end)
2727 --cursor_start;
2728 else
2729 ++cursor_start;
2730 }
2731 while (cursor_end > 0 && cursor_end < l)
2732 {
2733 if (s[cursor_end] == ' ')
2734 {
2735 if (cursor_end >= cursor_start)
2736 --cursor_end;
2737 else
2738 ++cursor_end;
2739 break;
2740 }
2741 if (cursor_end >= cursor_start)
2742 ++cursor_end;
2743 else
2744 --cursor_end;
2745 }
2746 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2747 d->flags |= D_DIRTY;
2748 }
2749 else
2750 {
2751 if (cursor_end == cursor_start) cursor_end = -1;
2752 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2753 }
2754 d->flags |= D_DIRTY;
2755 dclick = false;
2756 break;
2757 }
2758
2759 case MSG_WANTFOCUS:
2760 case MSG_LOSTFOCUS:
2761 case MSG_KEY:
2762 if(d->flags & (D_DISABLED|D_READONLY))
2763 break;
2764 return D_WANTFOCUS;
2765
2766 case MSG_CHAR:
2767 {
2768 if(d->flags & (D_DISABLED|D_READONLY))
2769 break;
2770 bool shifted = key_shifts & KB_SHIFT_FLAG;
2771 bool ctrl = key_shifts & KB_CTRL_CMD_FLAG;
2772 bool word_modifier = key_shifts & WORD_FLAG;
2773 bool line_modifier = key_shifts & LINE_FLAG;
2774 bool change_cursor = true;
2775 bool change_value = false;
2776 int scursor = cursor_start, ecursor = cursor_end;
2777 bool range_selected = cursor_end > -1;
2778 auto upper_c = c>>8;
2779 auto lower_c = c&0xFF;
2780
2781 if(shifted)
2782 {
2783 if(ecursor < 0)
2784 ecursor = scursor;
2785 }
2786 if(upper_c == KEY_LEFT)
2787 {
2788 if(shifted)
2789 {
2790 if(ecursor>0)
2791 --ecursor;
2792 }
2793 else
2794 {
2795 ecursor = -1;
2796 if(scursor > 0)
2797 --scursor;
2798 }
2799 }
2800 else if(upper_c == KEY_RIGHT)
2801 {
2802 if(shifted)
2803 {
2804 if(ecursor < l)
2805 ++ecursor;
2806 }
2807 else
2808 {
2809 ecursor = -1;
2810 if(scursor < l)
2811 ++scursor;
2812 }
2813 }
2814 else if(upper_c == KEY_HOME)
2815 {
2816 if(shifted)
2817 ecursor = 0;
2818 else
2819 {
2820 ecursor = -1;
2821 scursor = 0;
2822 }
2823 }
2824 else if(upper_c == KEY_END)
2825 {
2826 if(shifted)
2827 ecursor = l;
2828 else
2829 {
2830 ecursor = -1;
2831 scursor = l;
2832 }
2833 }
2834 else if(upper_c == KEY_DEL)
2835 {
2836 if(ctrl)
2837 {
2838 s[0] = 0;
2839 scursor = 0;
2840 ecursor = -1;
2841 GUI_EVENT(d, geCHANGE_VALUE);
2842 change_value = true;
2843 }
2844 else if(range_selected)
2845 {
2846 ecursor = -1;
2847 scursor = low_cursor;
2848 int ind = low_cursor, ind2 = high_cursor+1;
2849 ind2 = std::min(ind2, d->d1 - 1);
2850 while(s[ind2])
2851 s[ind++] = s[ind2++];
2852 while(s[ind])
2853 s[ind++] = 0;
2854 GUI_EVENT(d, geCHANGE_VALUE);
2855 change_value = true;
2856 }
2857 else if(scursor < l)
2858 {
2859 for(p=scursor; s[p]; p++)
2860 s[p] = s[p+1];
2861 GUI_EVENT(d, geCHANGE_VALUE);
2862 change_value = true;
2863 }
2864 }
2865 else if(upper_c == KEY_BACKSPACE)
2866 {
2867 if(line_modifier)
2868 {
2869 delete_line(s, &scursor);
2870 ecursor = -1;
2871 GUI_EVENT(d, geCHANGE_VALUE);
2872 change_value = true;
2873 }
2874 else if(word_modifier)
2875 {
2876 delete_word(s, &scursor);
2877 ecursor = -1;
2878 GUI_EVENT(d, geCHANGE_VALUE);
2879 change_value = true;
2880 }
2881 else if(range_selected)
2882 {
2883 ecursor = -1;
2884 scursor = low_cursor;
2885 size_t ind = low_cursor, ind2 = high_cursor+1;
2886 while(ind2 < l && s[ind2])
2887 s[ind++] = s[ind2++];
2888 while(s[ind])
2889 s[ind++] = 0;
2890 GUI_EVENT(d, geCHANGE_VALUE);
2891 change_value = true;
2892 }
2893 else if(scursor > 0)
2894 {
2895 --scursor;
2896 for(p=scursor; s[p]; p++)
2897 s[p] = s[p+1];
2898 GUI_EVENT(d, geCHANGE_VALUE);
2899 change_value = true;
2900 }
2901 }
2902 else if(upper_c == KEY_ENTER)
2903 {
2904 change_cursor = false;
2905 GUI_EVENT(d, geENTER);
2906 if(d->flags & D_EXIT)
2907 {
2908 object_message(d, MSG_DRAW, 0);
2909 return D_CLOSE;
2910 }
2911 else
2912 return D_O_K;
2913 }
2914 else if(upper_c == KEY_TAB)
2915 {
2916 change_cursor = false;
2917 return D_O_K;
2918 }
2919 else if (ctrl && upper_c == KEY_C)
2920 {
2921 change_cursor = false;
2922 std::ostringstream oss;
2923 if(range_selected)
2924 {
2925 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2926 {
2927 if(s[ind])
2928 oss << s[ind];
2929 }
2930 }
2931 else
2932 {
2933 if(s[scursor])
2934 oss << s[scursor];
2935 }
2936 set_al_clipboard(oss.str());
2937 }
2938 else if (ctrl && upper_c == KEY_V && clipboard_has_text())
2939 {
2940 std::string cb;
2941 if(get_al_clipboard(cb))
2942 {
2943 int ind = low_cursor, ind2 = high_cursor + 1;
2944 if (range_selected)
2945 {
2946 //Delete selected text
2947 ecursor = -1;
2948 scursor = low_cursor;
2949 while (s[ind2] && ind2 < l)
2950 s[ind++] = s[ind2++];
2951 while (s[ind])
2952 s[ind++] = 0;
2953 l = (int32_t)strlen(s);
2954 }
2955 //Move the text out of the way of the pasting
2956 int paste_len = cb.size();
2957 int paste_start = scursor;
2958 int paste_end = paste_start+paste_len;
2959 ind = strlen(s);
2960 ind2 = ind+paste_len;
2961 while(ind2 > d->d1)
2962 {
2963 --ind;
2964 --ind2;
2965 }
2966 size_t new_l = ind2;
2967 while(ind >= paste_start)
2968 {
2969 if(s[ind] || (ind&&s[ind-1]))
2970 {
2971 s[ind2] = s[ind];
2972 }
2973 --ind2; --ind;
2974 }
2975 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2976 {
2977 s[paste_start+q] = cb.at(q);
2978 }
2979 s[new_l] = 0;
2980 scursor = paste_start + paste_len;
2981 ecursor = -1;
2982 GUI_EVENT(d, geCHANGE_VALUE);
2983 change_value = true;
2984 }
2985 }
2986 else if (ctrl && upper_c == KEY_A)
2987 {
2988 cursor_start = 0;
2989 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2990 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2991 d->flags |= D_DIRTY;
2992 break;
2993 }
2994 else if(lower_c >= 32 && !ctrl)
2995 {
2996 if(range_selected)
2997 {
2998 //Delete selected text
2999 ecursor = -1;
3000 scursor = low_cursor;
3001 int ind = low_cursor, ind2 = high_cursor+1;
3002 // ind2 = std::min(ind2, d->d1);
3003 while(s[ind2] && ind2 < l)
3004 s[ind++] = s[ind2++];
3005 while(s[ind])
3006 s[ind++] = 0;
3007 l = (int32_t)strlen(s);
3008 //Type the character in its' place
3009 //(fallthrough)
3010 }
3011 if(l < d->d1)
3012 {
3013 ecursor = -1;
3014 s[l+1] = 0;
3015 size_t ind = l;
3016 while(ind >= scursor)
3017 {
3018 s[ind+1] = s[ind];
3019 if (!ind) break;
3020 --ind;
3021 }
3022
3023 s[scursor++] = lower_c;
3024
3025 GUI_EVENT(d, geCHANGE_VALUE);
3026 change_value = true;
3027 }
3028 }
3029 else
3030 return D_O_K;
3031 if(change_cursor)
3032 {
3033 cursor_end = ecursor; cursor_start = scursor;
3034 if (cursor_end == cursor_start) cursor_end = -1;
3035 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
3036 }
3037 /* if we changed something, better redraw... */
3038 // Note: this still redraws when not necessary.
3039 if (change_value || change_cursor)
3040 d->flags |= D_DIRTY;
3041 return D_USED_CHAR;
3042 }
3043 }
3044 return D_O_K;
3045 }
3046
3047 int32_t jwin_hexedit_proc_old(int32_t msg,DIALOG *d,int32_t c)
3048 {
3049 if(msg==MSG_CHAR)
3050 if(((isalpha(c&255) && !isxdigit(c&255))) || ispunct(c&255))
3051 return D_USED_CHAR;
3052
3053 return jwin_edit_proc(msg,d,isalpha(c&255)?c&0xDF:c);
3054 }
3055
3056 bool editproc_special_key(int32_t c)
3057 {
3058 switch(c>>8)
3059 {
3060 case KEY_LEFT: case KEY_RIGHT:
3061 case KEY_HOME: case KEY_END:
3062 case KEY_DEL: case KEY_BACKSPACE:
3063 case KEY_ENTER: case KEY_TAB:
3064 return true;
3065 }
3066 if(key_shifts & KB_CTRL_CMD_FLAG)
3067 switch(c&255)
3068 {
3069 case 'c': case 'C':
3070 return true;
3071 case 'v': case 'V':
3072 return clipboard_has_text();
3073 }
3074 return false;
3075 }
3076 bool editproc_combined_key(int32_t c)
3077 {
3078 if(key_shifts & KB_CTRL_CMD_FLAG)
3079 switch(c&255)
3080 {
3081 case 'c': case 'C':
3082 return true;
3083 case 'v': case 'V':
3084 return clipboard_has_text();
3085 }
3086 return false;
3087 }
3088 int32_t jwin_hexedit_proc(int32_t msg,DIALOG *d,int32_t c)
3089 {
3090 bool caps_paste = false;
3091 if(msg==MSG_CHAR)
3092 {
3093 if(key_shifts & KB_CTRL_CMD_FLAG)
3094 {
3095 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3096 {
3097 std::string cb;
3098 if(get_al_clipboard(cb))
3099 {
3100 if(cb.find_first_not_of("-.0123456789ABCDEFabcdef") != std::string::npos)
3101 return D_USED_CHAR;
3102 if(cb.find_first_of("abcdef") != std::string::npos)
3103 caps_paste = true;
3104 }
3105 else return D_USED_CHAR;
3106 }
3107 }
3108 switch(c&255)
3109 {
3110 case '-': case '.':
3111 case '0': case '1': case '2': case '3': case '4':
3112 case '5': case '6': case '7': case '8': case '9':
3113 case 'A': case 'B': case 'C':
3114 case 'D': case 'E': case 'F':
3115 break;
3116 case 'a': case 'b': case 'c':
3117 case 'd': case 'e': case 'f':
3118 c = (c&~255)|toupper(c&255);
3119 break;
3120 default:
3121 if(!editproc_special_key(c))
3122 return D_O_K;
3123 else if(!editproc_combined_key(c))
3124 c&=~255;
3125 }
3126 }
3127
3128 auto ret = jwin_edit_proc(msg,d,c);
3129 if(caps_paste)
3130 {
3131 char* s = (char*)d->dp;
3132 caps_paste = false;
3133 for(int q = strlen(s)-1; q >= 0; --q)
3134 {
3135 switch(s[q])
3136 {
3137 case 'a': case 'b': case 'c':
3138 case 'd': case 'e': case 'f':
3139 s[q] = toupper(s[q]);
3140 caps_paste = true;
3141 break;
3142 }
3143 }
3144 if(caps_paste)
3145 {
3146 jwin_edit_proc(MSG_DRAW,d,0);
3147 }
3148 }
3149 return ret;
3150 }
3151 int32_t jwin_numedit_proc(int32_t msg,DIALOG *d,int32_t c)
3152 {
3153 if(msg==MSG_CHAR)
3154 {
3155 if(key_shifts & KB_CTRL_CMD_FLAG)
3156 {
3157 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3158 {
3159 std::string cb;
3160 if(get_al_clipboard(cb))
3161 {
3162 if(cb.find_first_not_of("-.0123456789") != std::string::npos)
3163 return D_USED_CHAR;
3164 }
3165 else return D_USED_CHAR;
3166 }
3167 }
3168 switch(c&255)
3169 {
3170 case '-': case '.':
3171 case '0': case '1': case '2': case '3': case '4':
3172 case '5': case '6': case '7': case '8': case '9':
3173 break;
3174 default:
3175 if(!editproc_special_key(c))
3176 return D_O_K;
3177 else if(!editproc_combined_key(c))
3178 c&=~255;
3179 }
3180 }
3181
3182 return jwin_edit_proc(msg,d,c);
3183 }
3184
3185 int32_t jwin_numedit_byte_proc(int32_t msg,DIALOG *d,int32_t c)
3186 {
3187 if ( (atoi((char*)d->dp)) > 255 )
3188 {
3189 strcpy((char*)d->dp,"255\0");
3190 return jwin_numedit_proc(msg,d,c);
3191 }
3192 else if ( (atoi((char*)d->dp)) < 0 )
3193 {
3194 strcpy((char*)d->dp,"0\0");
3195 return jwin_numedit_proc(msg,d,c);
3196 }
3197
3198 return jwin_numedit_proc(msg,d,c);
3199 }
3200
3201 int32_t jwin_numedit_short_proc(int32_t msg,DIALOG *d,int32_t c)
3202 {
3203 if ( (atoi((char*)d->dp)) > 65535 )
3204 {
3205 strcpy((char*)d->dp,"65535\0");
3206 return jwin_numedit_proc(msg,d,c);
3207 }
3208 else if ( (atoi((char*)d->dp)) < 0 )
3209 {
3210 strcpy((char*)d->dp,"0\0");
3211 return jwin_numedit_proc(msg,d,c);
3212 }
3213
3214 return jwin_numedit_proc(msg,d,c);
3215 }
3216
3217 int32_t jwin_numedit_zscriptint_proc(int32_t msg,DIALOG *d,int32_t c)
3218 {
3219 if ( (atoi((char*)d->dp)) > 214748 )
3220 {
3221 strcpy((char*)d->dp,"214748\0");
3222 return jwin_numedit_proc(msg,d,c);
3223 }
3224 else if ( (atoi((char*)d->dp)) < -214748 )
3225 {
3226 strcpy((char*)d->dp,"-214748\0");
3227 return jwin_numedit_proc(msg,d,c);
3228 }
3229
3230 return jwin_numedit_proc(msg,d,c);
3231 }
3232
3233 int32_t jwin_numedit_sshort_proc(int32_t msg,DIALOG *d,int32_t c)
3234 {
3235 if ( (atoi((char*)d->dp)) > 32767 )
3236 {
3237 strcpy((char*)d->dp,"32767\0");
3238 return jwin_numedit_proc(msg,d,c);
3239 }
3240 else if ( (atoi((char*)d->dp)) < -32768 )
3241 {
3242 strcpy((char*)d->dp,"-32768\0");
3243 return jwin_numedit_proc(msg,d,c);
3244 }
3245
3246 return jwin_numedit_proc(msg,d,c);
3247 }
3248
3249 int32_t jwin_numedit_sbyte_proc(int32_t msg,DIALOG *d,int32_t c)
3250 {
3251 if ( (atoi((char*)d->dp)) > 127 )
3252 {
3253 strcpy((char*)d->dp,"127\0");
3254 return jwin_numedit_proc(msg,d,c);
3255 }
3256 else if ( (atoi((char*)d->dp)) < -128 )
3257 {
3258 strcpy((char*)d->dp,"-128\0");
3259 return jwin_numedit_proc(msg,d,c);
3260 }
3261
3262 return jwin_numedit_proc(msg,d,c);
3263 }
3264
3265 // Special numedit procs
3266
3267 void trim_trailing_0s(char* str, bool leaveDec = false)
3268 {
3269 bool foundDec = false;
3270 for(int32_t q = 0; str[q]; ++q)
3271 {
3272 if(str[q] == '.')
3273 {
3274 foundDec = true;
3275 break;
3276 }
3277 }
3278 if(!foundDec) return; //No decimal place, thus no trailing 0's.
3279 for(int32_t q = strlen(str)-1; q > 0; --q)
3280 {
3281 if(str[q] == '0' && (!leaveDec || str[q-1] != '.'))
3282 {
3283 str[q] = 0;
3284 }
3285 else if(str[q] == '.')
3286 {
3287 str[q] = 0;
3288 return;
3289 }
3290 else return;
3291 }
3292 }
3293 int32_t jwin_swapbtn_proc(int32_t msg, DIALOG* d, int32_t c)
3294 {
3295 static const char* swp[nswapMAX] = {"D", "H", "LD", "LH", "B"};
3296 d->dp = (void*)swp[d->d1&0xF];
3297 //d1 is (0xF0 = old val, 0x0F = new val)
3298 //d2 is max val
3299 if(d->d2 < 2 || d->d2 > nswapMAX) return D_O_K; //Not setup yet, or bad value
3300 DIALOG* relproc = (DIALOG*)d->dp3;
3301 GUI::TextField *tf_obj = nullptr;
3302 if(d->d2 > nswapBOOL) tf_obj = (GUI::TextField*)relproc->dp3;
3303 int32_t ret = jwin_button_proc(msg, d, c);
3304 if(d->flags & D_SELECTED) //On selection
3305 {
3306 d->d1 = ((d->d1&0x0F)<<4) | (((d->d1&0x0F)+1)%d->d2);
3307 d->dp = (void*)swp[d->d1&0xF];
3308 d->flags &= ~D_SELECTED;
3309 if(tf_obj) tf_obj->refresh_cb_swap();
3310 if(relproc)
3311 {
3312 object_message(relproc, MSG_DRAW, 0);
3313 }
3314 object_message(d, MSG_DRAW, 0);
3315 }
3316 return ret;
3317 }
3318 int32_t jwin_numedit_swap_byte_proc(int32_t msg, DIALOG *d, int32_t c)
3319 {
3320 DIALOG* swapbtn;
3321 if(d->flags&D_NEW_GUI)
3322 {
3323 swapbtn = d+1;
3324 }
3325 else swapbtn = (DIALOG*)d->dp3;
3326 if(!swapbtn) return D_O_K;
3327 if(msg==MSG_START) //Setup the swapbtn
3328 {
3329 d->bg = 0;
3330 swapbtn->d2 = 2; //Max states
3331 auto ty = swapbtn->d1&0xF;
3332 if(unsigned(ty) > swapbtn->d2)
3333 swapbtn->d1 &= ~0xF;
3334 swapbtn->dp3 = (void*)d;
3335 }
3336 int32_t ret = D_O_K;
3337 int32_t ntype = swapbtn->d1&0xF,
3338 otype = swapbtn->d1>>4;
3339
3340 char* str = (char*)d->dp;
3341 int32_t v = 0;
3342 if(msg == MSG_START)
3343 v = d->fg;
3344 else switch(otype)
3345 {
3346 case nswapDEC:
3347 v = atoi(str);
3348 break;
3349 case nswapHEX:
3350 v = zc_xtoi(str);
3351 break;
3352 }
3353 byte b;
3354 if ( v > 255 )
3355 b=255;
3356 else if ( v < 0 )
3357 b=0;
3358 else b = (byte)v;
3359 if(msg==MSG_CHAR && ((c&255)=='-'))
3360 {
3361 //unsigned//b = -b;
3362 c &= ~255;
3363 }
3364 if(unsigned(v) != b || otype != ntype || msg == MSG_START)
3365 {
3366 switch(ntype)
3367 {
3368 case nswapDEC:
3369 sprintf(str, "%d", b);
3370 break;
3371 case nswapHEX:
3372 sprintf(str, "%X", b);
3373 break;
3374 }
3375 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3376 }
3377
3378 if(d->fg != b)
3379 {
3380 d->fg = b; //Store numeric data
3381 GUI_EVENT(d, geUPDATE_SWAP);
3382 }
3383 switch(ntype)
3384 {
3385 case nswapDEC:
3386 d->d1 = 3; //3 digits max
3387 ret |= jwin_numedit_proc(msg, d, c);
3388 break;
3389 case nswapHEX:
3390 d->d1 = 2; //2 digits max
3391 if(msg == MSG_CHAR && isalpha(c&255)) //always capitalize
3392 c = (c&~255) | (toupper(c&255));
3393 ret |= jwin_hexedit_proc(msg, d, c);
3394 break;
3395 }
3396
3397 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3398
3399 return ret;
3400 }
3401 #define INC_TF_CURSORS(val,inc,max) \
3402 do \
3403 { \
3404 int32_t scursor = (val & 0xFFFF)+inc; \
3405 int32_t ecursor = (val & 0xFFFF0000) >> 16; \
3406 bool valid_ecursor = ecursor != 0xFFFF; \
3407 if(valid_ecursor) ecursor += inc; \
3408 if(inc < 0) \
3409 { \
3410 if(scursor < 0) scursor = 0; \
3411 if(valid_ecursor && ecursor < 0) ecursor = 0; \
3412 } \
3413 else \
3414 { \
3415 if(scursor > max) scursor = max; \
3416 if(valid_ecursor && ecursor > max) ecursor = max; \
3417 } \
3418 val = scursor | (ecursor<<16); \
3419 } while(false)
3420 int32_t jwin_numedit_swap_sshort_proc(int32_t msg, DIALOG *d, int32_t c)
3421 {
3422 const size_t maxlen = 7;
3423 DIALOG* swapbtn;
3424 if(d->flags&D_NEW_GUI)
3425 {
3426 swapbtn = d+1;
3427 }
3428 else swapbtn = (DIALOG*)d->dp3;
3429 if(!swapbtn) return D_O_K;
3430 if(msg==MSG_START) //Setup the swapbtn
3431 {
3432 d->bg = 0;
3433 swapbtn->d2 = 2; //Max states
3434 auto ty = swapbtn->d1&0xF;
3435 if(unsigned(ty) > swapbtn->d2)
3436 swapbtn->d1 &= ~0xF;
3437 swapbtn->dp3 = (void*)d;
3438 }
3439 int32_t ret = D_O_K;
3440 int32_t ntype = swapbtn->d1&0xF,
3441 otype = swapbtn->d1>>4;
3442
3443 char* str = (char*)d->dp;
3444 int32_t v = 0;
3445 if(msg == MSG_START)
3446 v = d->fg;
3447 else switch(otype)
3448 {
3449 case nswapDEC:
3450 v = atoi(str);
3451 break;
3452 case nswapHEX:
3453 v = zc_xtoi(str);
3454 break;
3455 }
3456 int16_t b;
3457 if ( v > 32767 )
3458 b=32767;
3459 else if ( v < -32768 )
3460 b=-32768;
3461 else b = (int16_t)v;
3462 bool queued_neg = d->bg;
3463 if(msg==MSG_CHAR && ((c&255)=='-'))
3464 {
3465 if(b)
3466 {
3467 b = -b;
3468 v = b;
3469 if(b<0)
3470 {
3471 if(str[0] != '-')
3472 {
3473 char buf[16] = {0};
3474 strcpy(buf, str);
3475 sprintf(str, "-%s", buf);
3476 INC_TF_CURSORS(d->d2,1,strlen(str));
3477 }
3478 }
3479 else if(str[0] == '-')
3480 {
3481 char buf[16] = {0};
3482 strcpy(buf, str);
3483 sprintf(str, "%s", buf+1);
3484 INC_TF_CURSORS(d->d2,-1,strlen(str));
3485 }
3486 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3487 }
3488 else queued_neg = !queued_neg; //queue the negative
3489 c &= ~255;
3490 ret |= D_USED_CHAR;
3491 }
3492 if(b && queued_neg)
3493 {
3494 //b = -b; //actually, 'atoi' handles it for us.....
3495 queued_neg = false;
3496 }
3497 if(bool(d->bg) != queued_neg)
3498 {
3499 d->bg = queued_neg;
3500 if(queued_neg)
3501 {
3502 if(str[0] != '-')
3503 {
3504 char buf[16] = {0};
3505 strcpy(buf, str);
3506 sprintf(str, "-%s", buf);
3507 INC_TF_CURSORS(d->d2,1,strlen(str));
3508 }
3509 }
3510 else if(!b && str[0] == '-')
3511 {
3512 char buf[16] = {0};
3513 strcpy(buf, str);
3514 sprintf(str, "%s", buf+1);
3515 INC_TF_CURSORS(d->d2,-1,strlen(str));
3516 }
3517 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3518 }
3519 if(v != b || otype != ntype || msg == MSG_START)
3520 {
3521 switch(ntype)
3522 {
3523 case nswapDEC:
3524 sprintf(str, "%d", b);
3525 break;
3526 case nswapHEX:
3527 if(b<0)
3528 sprintf(str, "-%X", -b);
3529 else sprintf(str, "%X", b);
3530 break;
3531 }
3532 d->d2 = 0xFFFF0000|strlen(str);
3533 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3534 }
3535
3536 if(d->fg != b)
3537 {
3538 d->fg = b; //Store numeric data
3539 GUI_EVENT(d, geUPDATE_SWAP);
3540 }
3541 bool rev_d2 = false;
3542 int32_t old_d2 = d->d2;
3543 int32_t ref_d2;
3544 if(msg == MSG_CHAR && queued_neg)
3545 {
3546 auto scursor = d->d2 & 0xFFFF;
3547 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3548 if(!scursor)
3549 {
3550 rev_d2 = true;
3551 INC_TF_CURSORS(d->d2,1,strlen(str));
3552 ref_d2 = d->d2;
3553 }
3554 }
3555 switch(ntype)
3556 {
3557 case nswapDEC:
3558 d->d1 = 6; //6 digits max (incl '-')
3559 ret |= jwin_numedit_proc(msg, d, c);
3560 break;
3561 case nswapHEX:
3562 d->d1 = 5; //5 digits max (incl '-')
3563 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3564 c = (c&~255) | (toupper(c&255));
3565 ret |= jwin_hexedit_proc(msg, d, c);
3566 break;
3567 }
3568 if(rev_d2 && ref_d2 == d->d2)
3569 {
3570 d->d2 = old_d2;
3571 }
3572
3573 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3574
3575 return ret;
3576 }
3577 int32_t jwin_numedit_swap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
3578 {
3579 const size_t maxlen = 13;
3580 DIALOG* swapbtn;
3581 if(d->flags&D_NEW_GUI)
3582 {
3583 swapbtn = d+1;
3584 }
3585 else swapbtn = (DIALOG*)d->dp3;
3586 if(!swapbtn) return D_O_K;
3587 if(msg==MSG_START) //Setup the swapbtn
3588 {
3589 d->bg = 0;
3590 swapbtn->d2 = 4; //Max states
3591 auto ty = swapbtn->d1&0xF;
3592 if(unsigned(ty) > swapbtn->d2)
3593 swapbtn->d1 &= ~0xF;
3594 swapbtn->dp3 = (void*)d;
3595 }
3596 int32_t ret = D_O_K;
3597 int32_t ntype = swapbtn->d1&0xF,
3598 otype = swapbtn->d1>>4;
3599
3600 char* str = (char*)d->dp;
3601 int64_t v = 0;
3602 if(msg == MSG_START)
3603 v = d->fg;
3604 else switch(otype)
3605 {
3606 case nswapDEC:
3607 if(char *ptr = strchr(str, '.'))
3608 {
3609 char tempstr[32] = {0};
3610 strcpy(tempstr, str);
3611 for(int32_t q = 0; q < 4; ++q)
3612 tempstr[strlen(str)+q]='0';
3613 ptr = strchr(tempstr, '.');
3614 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3615 v = atoi(tempstr);
3616 v *= 10000;
3617 if(tempstr[0] == '-')
3618 v -= atoi(ptr);
3619 else v += atoi(ptr);
3620 }
3621 else
3622 {
3623 v = atoi(str);
3624 v *= 10000;
3625 }
3626 break;
3627 case nswapHEX:
3628 if(char *ptr = strchr(str, '.'))
3629 {
3630 char tempstr[32] = {0};
3631 strcpy(tempstr, str);
3632 for(int32_t q = 0; q < 4; ++q)
3633 tempstr[strlen(str)+q]='0';
3634 ptr = strchr(tempstr, '.');
3635 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3636 v = zc_xtoi(tempstr);
3637 v *= 10000;
3638 if(tempstr[0] == '-')
3639 v -= atoi(ptr);
3640 else v += atoi(ptr);
3641 }
3642 else
3643 {
3644 v = zc_xtoi(str);
3645 v *= 10000;
3646 }
3647 break;
3648 case nswapLDEC:
3649 v = zc_atoi64(str);
3650 break;
3651 case nswapLHEX:
3652 v = zc_xtoi64(str);
3653 break;
3654 }
3655 int32_t b;
3656 if ( v > 2147483647 )
3657 b=2147483647;
3658 else if ( v < INT_MIN )
3659 b=INT_MIN;
3660 else b = (int32_t)v;
3661 bool queued_neg = d->bg;
3662 if(msg==MSG_CHAR && ((c&255)=='-'))
3663 {
3664 if(b)
3665 {
3666 if(b==INT_MIN)
3667 ++b;
3668 b = -b;
3669 v = b;
3670 if(b<0)
3671 {
3672 if(str[0] != '-')
3673 {
3674 char buf[16] = {0};
3675 strcpy(buf, str);
3676 sprintf(str, "-%s", buf);
3677 INC_TF_CURSORS(d->d2,1,strlen(str));
3678 }
3679 }
3680 else if(str[0] == '-')
3681 {
3682 char buf[16] = {0};
3683 strcpy(buf, str);
3684 sprintf(str, "%s", buf+1);
3685 INC_TF_CURSORS(d->d2,-1,strlen(str));
3686 }
3687 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3688 }
3689 else queued_neg = !queued_neg; //queue negative
3690 c &= ~255;
3691 ret |= D_USED_CHAR;
3692 }
3693 if(b && queued_neg)
3694 {
3695 //b = -b; //actually, 'atoi' handles it for us.....
3696 queued_neg = false;
3697 }
3698 if(bool(d->bg) != queued_neg)
3699 {
3700 d->bg = queued_neg;
3701 if(queued_neg)
3702 {
3703 if(str[0] != '-')
3704 {
3705 char buf[16] = {0};
3706 strcpy(buf, str);
3707 sprintf(str, "-%s", buf);
3708 INC_TF_CURSORS(d->d2,1,strlen(str));
3709 }
3710 }
3711 else if(!b && str[0] == '-')
3712 {
3713 char buf[16] = {0};
3714 strcpy(buf, str);
3715 sprintf(str, "%s", buf+1);
3716 INC_TF_CURSORS(d->d2,-1,strlen(str));
3717 }
3718 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3719 }
3720 if(v != b || otype != ntype || msg == MSG_START)
3721 {
3722 switch(ntype)
3723 {
3724 case nswapDEC:
3725 if(b < 0)
3726 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
3727 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
3728 trim_trailing_0s(str);
3729 break;
3730 case nswapHEX:
3731 if(b<0)
3732 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
3733 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
3734 trim_trailing_0s(str);
3735 break;
3736 case nswapLDEC:
3737 sprintf(str, "%d", b);
3738 break;
3739 case nswapLHEX:
3740 if(b<0)
3741 sprintf(str, "-%X", -b);
3742 else sprintf(str, "%X", b);
3743 break;
3744 }
3745 d->d2 = 0xFFFF0000|strlen(str);
3746 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3747 }
3748 if(d->fg != b)
3749 {
3750 d->fg = b; //Store numeric data
3751 GUI_EVENT(d, geUPDATE_SWAP);
3752 }
3753 if(msg==MSG_CHAR && ((c&255)=='.'))
3754 {
3755 if(ntype >= nswapLDEC) //No '.' in long modes
3756 c&=~255;
3757 else
3758 {
3759 for(int32_t q = 0; str[q]; ++q)
3760 {
3761 if(str[q] == '.') //Only one '.'
3762 {
3763 c&=~255;
3764 break;
3765 }
3766 }
3767 }
3768 }
3769 bool rev_d2 = false;
3770 int32_t old_d2 = d->d2;
3771 int32_t ref_d2;
3772 if(msg == MSG_CHAR && queued_neg)
3773 {
3774 auto scursor = d->d2 & 0xFFFF;
3775 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3776 if(!scursor)
3777 {
3778 rev_d2 = true;
3779 INC_TF_CURSORS(d->d2,1,strlen(str));
3780 ref_d2 = d->d2;
3781 }
3782 }
3783 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3784 switch(ntype)
3785 {
3786 case nswapDEC:
3787 d->d1 = 12; //12 digits max (incl '-', '.')
3788 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
3789 {
3790 int32_t p = 0;
3791 for(int32_t q = 0; str[q]; ++q)
3792 {
3793 if(str[q]=='.')
3794 {
3795 if((d->d2&0x0000FFFF) <= q)
3796 break; //typing before the '.'
3797 ++p;
3798 }
3799 else if(p) ++p;
3800 }
3801 if(p>=5) //too many chars after '.'
3802 c&=~255;
3803 }
3804 ret |= jwin_numedit_proc(msg, d, c);
3805 break;
3806 case nswapHEX:
3807 d->d1 = 11; //11 digits max (incl '-', '.')
3808 if(msg==MSG_CHAR && !editproc_special_key(c))
3809 {
3810 if(!((c&255)=='.'||isxdigit(c&255)))
3811 c&=~255;
3812 else if(isxdigit(c&255) && !isdigit(c&255))
3813 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
3814 {
3815 if(str[q] == '.') //No hex digits to the right of the '.'
3816 {
3817 c&=~255;
3818 break;
3819 }
3820 }
3821 if((c&255) && !areaselect)
3822 {
3823 int32_t p = 0;
3824 for(int32_t q = 0; str[q]; ++q)
3825 {
3826 if(str[q]=='.')
3827 {
3828 if((d->d2&0x0000FFFF) <= q)
3829 break; //typing before the '.'
3830 ++p;
3831 }
3832 else if(p) ++p;
3833 }
3834 if(p>=5) //too many chars after '.'
3835 c&=~255;
3836 }
3837 if(isalpha(c&255)) //always capitalize
3838 c = (c&~255) | (toupper(c&255));
3839 }
3840 ret |= jwin_hexedit_proc(msg, d, c);
3841 break;
3842 case nswapLDEC:
3843 d->d1 = 11; //11 digits max (incl '-')
3844 ret |= jwin_numedit_proc(msg, d, c);
3845 break;
3846 case nswapLHEX:
3847 d->d1 = 9; //9 digits max (incl '-')
3848 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3849 c = (c&~255) | (toupper(c&255));
3850 ret |= jwin_hexedit_proc(msg, d, c);
3851 break;
3852 }
3853 if(rev_d2 && ref_d2 == d->d2)
3854 {
3855 d->d2 = old_d2;
3856 }
3857
3858 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3859
3860 return ret;
3861 }
3862 int32_t jwin_numedit_swap_zsint_nodec_proc(int32_t msg, DIALOG *d, int32_t c)
3863 {
3864 const size_t maxlen = 7;
3865 DIALOG* swapbtn;
3866 if(d->flags&D_NEW_GUI)
3867 {
3868 swapbtn = d+1;
3869 }
3870 else swapbtn = (DIALOG*)d->dp3;
3871 if(!swapbtn) return D_O_K;
3872 if(msg==MSG_START) //Setup the swapbtn
3873 {
3874 d->bg = 0;
3875 swapbtn->d2 = 2; //Max states
3876 auto ty = swapbtn->d1&0xF;
3877 if(unsigned(ty) > swapbtn->d2)
3878 swapbtn->d1 &= ~0xF;
3879 swapbtn->dp3 = (void*)d;
3880 }
3881 int32_t ret = D_O_K;
3882 int32_t ntype = swapbtn->d1&0xF,
3883 otype = swapbtn->d1>>4;
3884
3885 char* str = (char*)d->dp;
3886 int64_t v = 0;
3887 if(msg == MSG_START)
3888 v = d->fg;
3889 else switch(otype)
3890 {
3891 case nswapDEC:
3892 v = atoi(str);
3893 v *= 10000;
3894 break;
3895 case nswapHEX:
3896 v = zc_xtoi(str);
3897 v *= 10000;
3898 break;
3899 }
3900 int32_t b;
3901 if ( v > 2147480000 )
3902 b=2147480000;
3903 else if ( v < -2147480000 )
3904 b=-2147480000;
3905 else b = (int32_t)v;
3906 bool queued_neg = d->bg;
3907 if(msg==MSG_CHAR && ((c&255)=='-'))
3908 {
3909 if(b)
3910 {
3911 if(b==INT_MIN)
3912 ++b;
3913 b = -b;
3914 v = b;
3915 if(b<0)
3916 {
3917 if(str[0] != '-')
3918 {
3919 char buf[16] = {0};
3920 strcpy(buf, str);
3921 sprintf(str, "-%s", buf);
3922 INC_TF_CURSORS(d->d2,1,strlen(str));
3923 }
3924 }
3925 else if(str[0] == '-')
3926 {
3927 char buf[16] = {0};
3928 strcpy(buf, str);
3929 sprintf(str, "%s", buf+1);
3930 INC_TF_CURSORS(d->d2,-1,strlen(str));
3931 }
3932 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3933 }
3934 else queued_neg = !queued_neg; //queue negative
3935 c &= ~255;
3936 ret |= D_USED_CHAR;
3937 }
3938 if(b && queued_neg)
3939 {
3940 //b = -b; //actually, 'atoi' handles it for us.....
3941 queued_neg = false;
3942 }
3943 if(bool(d->bg) != queued_neg)
3944 {
3945 d->bg = queued_neg;
3946 if(queued_neg)
3947 {
3948 if(str[0] != '-')
3949 {
3950 char buf[16] = {0};
3951 strcpy(buf, str);
3952 sprintf(str, "-%s", buf);
3953 INC_TF_CURSORS(d->d2,1,strlen(str));
3954 }
3955 }
3956 else if(!b && str[0] == '-')
3957 {
3958 char buf[16] = {0};
3959 strcpy(buf, str);
3960 sprintf(str, "%s", buf+1);
3961 INC_TF_CURSORS(d->d2,-1,strlen(str));
3962 }
3963 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3964 }
3965 if(v != b || otype != ntype || msg == MSG_START)
3966 {
3967 switch(ntype)
3968 {
3969 case nswapDEC:
3970 if(b < 0)
3971 sprintf(str, "-%ld", abs(b/10000L));
3972 else sprintf(str, "%ld", b/10000L);
3973 break;
3974 case nswapHEX:
3975 if(b<0)
3976 sprintf(str, "-%lX", abs(b/10000L));
3977 else sprintf(str, "%lX", b/10000L);
3978 break;
3979 }
3980 d->d2 = 0xFFFF0000|strlen(str);
3981 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3982 }
3983 if(d->fg != b)
3984 {
3985 d->fg = b; //Store numeric data
3986 GUI_EVENT(d, geUPDATE_SWAP);
3987 }
3988 if(msg==MSG_CHAR && ((c&255)=='.'))
3989 {
3990 c&=~255; //no '.' in nodec version
3991 }
3992 bool rev_d2 = false;
3993 int32_t old_d2 = d->d2;
3994 int32_t ref_d2;
3995 if(msg == MSG_CHAR && queued_neg)
3996 {
3997 auto scursor = d->d2 & 0xFFFF;
3998 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3999 if(!scursor)
4000 {
4001 rev_d2 = true;
4002 INC_TF_CURSORS(d->d2,1,strlen(str));
4003 ref_d2 = d->d2;
4004 }
4005 }
4006 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4007 switch(ntype)
4008 {
4009 case nswapDEC:
4010 d->d1 = 7; //7 digits max (incl '-')
4011 ret |= jwin_numedit_proc(msg, d, c);
4012 break;
4013 case nswapHEX:
4014 d->d1 = 6; //6 digits max (incl '-')
4015 if(msg==MSG_CHAR && !editproc_special_key(c))
4016 {
4017 if(!isxdigit(c&255))
4018 c&=~255;
4019 if(isalpha(c&255)) //always capitalize
4020 c = (c&~255) | (toupper(c&255));
4021 }
4022 ret |= jwin_hexedit_proc(msg, d, c);
4023 break;
4024 }
4025 if(rev_d2 && ref_d2 == d->d2)
4026 {
4027 d->d2 = old_d2;
4028 }
4029
4030 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
4031
4032 return ret;
4033 }
4034 int32_t jwin_numedit_swap_zsint2_proc(int32_t msg, DIALOG *d, int32_t c)
4035 {
4036 const size_t maxlen = 13;
4037 DIALOG* swapbtn;
4038 ASSERT(d->flags&D_NEW_GUI);
4039 swapbtn = d+1;
4040 if(!swapbtn) return D_O_K;
4041 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
4042 if(!tf_obj) return D_O_K;
4043 if(msg==MSG_START) //Setup the swapbtn
4044 {
4045 d->bg = 0;
4046 swapbtn->d2 = 5; //Max states
4047 auto ty = swapbtn->d1&0xF;
4048 if(unsigned(ty) > swapbtn->d2)
4049 swapbtn->d1 &= ~0xF;
4050 swapbtn->dp3 = (void*)d;
4051 }
4052 int32_t ret = D_O_K;
4053 int32_t ntype = swapbtn->d1&0xF,
4054 otype = swapbtn->d1>>4;
4055 if(otype==nswapBOOL || ntype == nswapBOOL)
4056 {
4057 if(otype != ntype)
4058 {
4059 tf_obj->refresh_cb_swap();
4060 }
4061 if(ntype == nswapBOOL)
4062 {
4063 swapbtn->d1 = (ntype<<4)|ntype;
4064 return D_O_K;
4065 }
4066 }
4067
4068 char* str = (char*)d->dp;
4069 int64_t v = 0;
4070 if(msg == MSG_START)
4071 v = d->fg;
4072 else switch(otype)
4073 {
4074 case nswapDEC:
4075 if(char *ptr = strchr(str, '.'))
4076 {
4077 char tempstr[32] = {0};
4078 strcpy(tempstr, str);
4079 for(int32_t q = 0; q < 4; ++q)
4080 tempstr[strlen(str)+q]='0';
4081 ptr = strchr(tempstr, '.');
4082 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4083 v = atoi(tempstr);
4084 v *= 10000;
4085 if(tempstr[0] == '-')
4086 v -= atoi(ptr);
4087 else v += atoi(ptr);
4088 }
4089 else
4090 {
4091 v = atoi(str);
4092 v *= 10000;
4093 }
4094 break;
4095 case nswapHEX:
4096 if(char *ptr = strchr(str, '.'))
4097 {
4098 char tempstr[32] = {0};
4099 strcpy(tempstr, str);
4100 for(int32_t q = 0; q < 4; ++q)
4101 tempstr[strlen(str)+q]='0';
4102 ptr = strchr(tempstr, '.');
4103 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4104 v = zc_xtoi(tempstr);
4105 v *= 10000;
4106 if(tempstr[0] == '-')
4107 v -= atoi(ptr);
4108 else v += atoi(ptr);
4109 }
4110 else
4111 {
4112 v = zc_xtoi(str);
4113 v *= 10000;
4114 }
4115 break;
4116 case nswapLDEC:
4117 v = zc_atoi64(str);
4118 break;
4119 case nswapLHEX:
4120 v = zc_xtoi64(str);
4121 break;
4122 case nswapBOOL:
4123 v = d->fg;
4124 break;
4125 }
4126 int32_t b;
4127 if ( v > 2147483647 )
4128 b=2147483647;
4129 else if ( v < INT_MIN )
4130 b=INT_MIN;
4131 else b = (int32_t)v;
4132 bool queued_neg = d->bg;
4133 if(msg==MSG_CHAR && ((c&255)=='-'))
4134 {
4135 if(b)
4136 {
4137 if(b==INT_MIN)
4138 ++b;
4139 b = -b;
4140 v = b;
4141 if(b<0)
4142 {
4143 if(str[0] != '-')
4144 {
4145 char buf[16] = {0};
4146 strcpy(buf, str);
4147 sprintf(str, "-%s", buf);
4148 INC_TF_CURSORS(d->d2,1,strlen(str));
4149 }
4150 }
4151 else if(str[0] == '-')
4152 {
4153 char buf[16] = {0};
4154 strcpy(buf, str);
4155 sprintf(str, "%s", buf+1);
4156 INC_TF_CURSORS(d->d2,-1,strlen(str));
4157 }
4158 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4159 }
4160 else queued_neg = !queued_neg; //queue negative
4161 c &= ~255;
4162 ret |= D_USED_CHAR;
4163 }
4164 if(b && queued_neg)
4165 {
4166 //b = -b; //actually, 'atoi' handles it for us.....
4167 queued_neg = false;
4168 }
4169 if(bool(d->bg) != queued_neg)
4170 {
4171 d->bg = queued_neg;
4172 if(queued_neg)
4173 {
4174 if(str[0] != '-')
4175 {
4176 char buf[16] = {0};
4177 strcpy(buf, str);
4178 sprintf(str, "-%s", buf);
4179 INC_TF_CURSORS(d->d2,1,strlen(str));
4180 }
4181 }
4182 else if(!b && str[0] == '-')
4183 {
4184 char buf[16] = {0};
4185 strcpy(buf, str);
4186 sprintf(str, "%s", buf+1);
4187 INC_TF_CURSORS(d->d2,-1,strlen(str));
4188 }
4189 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4190 }
4191 if(v != b || otype != ntype || msg == MSG_START)
4192 {
4193 switch(ntype)
4194 {
4195 case nswapDEC:
4196 if(b < 0)
4197 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4198 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4199 trim_trailing_0s(str);
4200 break;
4201 case nswapHEX:
4202 if(b<0)
4203 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4204 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4205 trim_trailing_0s(str);
4206 break;
4207 case nswapLDEC:
4208 sprintf(str, "%d", b);
4209 break;
4210 case nswapLHEX:
4211 if(b<0)
4212 sprintf(str, "-%X", -b);
4213 else sprintf(str, "%X", b);
4214 break;
4215 }
4216 d->d2 = 0xFFFF0000|strlen(str);
4217 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4218 }
4219 if(d->fg != b)
4220 {
4221 d->fg = b; //Store numeric data
4222 GUI_EVENT(d, geUPDATE_SWAP);
4223 }
4224 if(msg==MSG_CHAR && ((c&255)=='.'))
4225 {
4226 if(ntype >= nswapLDEC) //No '.' in long modes
4227 c&=~255;
4228 else
4229 {
4230 for(int32_t q = 0; str[q]; ++q)
4231 {
4232 if(str[q] == '.') //Only one '.'
4233 {
4234 c&=~255;
4235 break;
4236 }
4237 }
4238 }
4239 }
4240 bool rev_d2 = false;
4241 int32_t old_d2 = d->d2;
4242 int32_t ref_d2;
4243 if(msg == MSG_CHAR && queued_neg)
4244 {
4245 auto scursor = d->d2 & 0xFFFF;
4246 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4247 if(!scursor)
4248 {
4249 rev_d2 = true;
4250 INC_TF_CURSORS(d->d2,1,strlen(str));
4251 ref_d2 = d->d2;
4252 }
4253 }
4254 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4255 switch(ntype)
4256 {
4257 case nswapDEC:
4258 d->d1 = 12; //12 digits max (incl '-', '.')
4259 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4260 {
4261 int32_t p = 0;
4262 for(int32_t q = 0; str[q]; ++q)
4263 {
4264 if(str[q]=='.')
4265 {
4266 if((d->d2&0x0000FFFF) <= q)
4267 break; //typing before the '.'
4268 ++p;
4269 }
4270 else if(p) ++p;
4271 }
4272 if(p>=5) //too many chars after '.'
4273 c&=~255;
4274 }
4275 ret |= jwin_numedit_proc(msg, d, c);
4276 break;
4277 case nswapHEX:
4278 d->d1 = 11; //11 digits max (incl '-', '.')
4279 if(msg==MSG_CHAR && !editproc_special_key(c))
4280 {
4281 if(!((c&255)=='.'||isxdigit(c&255)))
4282 c&=~255;
4283 else if(isxdigit(c&255) && !isdigit(c&255))
4284 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4285 {
4286 if(str[q] == '.') //No hex digits to the right of the '.'
4287 {
4288 c&=~255;
4289 break;
4290 }
4291 }
4292 if((c&255) && !areaselect)
4293 {
4294 int32_t p = 0;
4295 for(int32_t q = 0; str[q]; ++q)
4296 {
4297 if(str[q]=='.')
4298 {
4299 if((d->d2&0x0000FFFF) <= q)
4300 break; //typing before the '.'
4301 ++p;
4302 }
4303 else if(p) ++p;
4304 }
4305 if(p>=5) //too many chars after '.'
4306 c&=~255;
4307 }
4308 if(isalpha(c&255)) //always capitalize
4309 c = (c&~255) | (toupper(c&255));
4310 }
4311 ret |= jwin_hexedit_proc(msg, d, c);
4312 break;
4313 case nswapLDEC:
4314 d->d1 = 11; //11 digits max (incl '-')
4315 ret |= jwin_numedit_proc(msg, d, c);
4316 break;
4317 case nswapLHEX:
4318 d->d1 = 9; //9 digits max (incl '-')
4319 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4320 c = (c&~255) | (toupper(c&255));
4321 ret |= jwin_hexedit_proc(msg, d, c);
4322 break;
4323 }
4324 if(rev_d2 && ref_d2 == d->d2)
4325 {
4326 d->d2 = old_d2;
4327 }
4328
4329 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
4330
4331 if(msg==MSG_START)
4332 tf_obj->refresh_cb_swap();
4333
4334 return ret;
4335 }
4336 int32_t jwin_numedit_noswap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
4337 {
4338 const size_t maxlen = 13;
4339 ASSERT(d->flags&D_NEW_GUI);
4340 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
4341 if(!tf_obj) return D_O_K;
4342 int32_t ret = D_O_K;
4343 int32_t type = tf_obj->getSwapType();
4344
4345 char* str = (char*)d->dp;
4346 int64_t v = 0;
4347 if(msg == MSG_START)
4348 v = d->fg;
4349 else switch(type)
4350 {
4351 case nswapDEC:
4352 if(char *ptr = strchr(str, '.'))
4353 {
4354 char tempstr[32] = {0};
4355 strcpy(tempstr, str);
4356 for(int32_t q = 0; q < 4; ++q)
4357 tempstr[strlen(str)+q]='0';
4358 ptr = strchr(tempstr, '.');
4359 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4360 v = atoi(tempstr);
4361 v *= 10000;
4362 if(tempstr[0] == '-')
4363 v -= atoi(ptr);
4364 else v += atoi(ptr);
4365 }
4366 else
4367 {
4368 v = atoi(str);
4369 v *= 10000;
4370 }
4371 break;
4372 case nswapHEX:
4373 if(char *ptr = strchr(str, '.'))
4374 {
4375 char tempstr[32] = {0};
4376 strcpy(tempstr, str);
4377 for(int32_t q = 0; q < 4; ++q)
4378 tempstr[strlen(str)+q]='0';
4379 ptr = strchr(tempstr, '.');
4380 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4381 v = zc_xtoi(tempstr);
4382 v *= 10000;
4383 if(tempstr[0] == '-')
4384 v -= atoi(ptr);
4385 else v += atoi(ptr);
4386 }
4387 else
4388 {
4389 v = zc_xtoi(str);
4390 v *= 10000;
4391 }
4392 break;
4393 case nswapLDEC:
4394 v = zc_atoi64(str);
4395 break;
4396 case nswapLHEX:
4397 v = zc_xtoi64(str);
4398 break;
4399 case nswapBOOL:
4400 v = d->fg;
4401 break;
4402 }
4403 int32_t b;
4404 if ( v > 2147483647 )
4405 b=2147483647;
4406 else if ( v < INT_MIN )
4407 b=INT_MIN;
4408 else b = (int32_t)v;
4409 bool queued_neg = d->bg;
4410 if(msg==MSG_CHAR && ((c&255)=='-'))
4411 {
4412 if(b)
4413 {
4414 if(b==INT_MIN)
4415 ++b;
4416 b = -b;
4417 v = b;
4418 if(b<0)
4419 {
4420 if(str[0] != '-')
4421 {
4422 char buf[16] = {0};
4423 strcpy(buf, str);
4424 sprintf(str, "-%s", buf);
4425 INC_TF_CURSORS(d->d2,1,strlen(str));
4426 }
4427 }
4428 else if(str[0] == '-')
4429 {
4430 char buf[16] = {0};
4431 strcpy(buf, str);
4432 sprintf(str, "%s", buf+1);
4433 INC_TF_CURSORS(d->d2,-1,strlen(str));
4434 }
4435 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4436 }
4437 else queued_neg = !queued_neg; //queue negative
4438 c &= ~255;
4439 ret |= D_USED_CHAR;
4440 }
4441 if(b && queued_neg)
4442 {
4443 //b = -b; //actually, 'atoi' handles it for us.....
4444 queued_neg = false;
4445 }
4446 if(bool(d->bg) != queued_neg)
4447 {
4448 d->bg = queued_neg;
4449 if(queued_neg)
4450 {
4451 if(str[0] != '-')
4452 {
4453 char buf[16] = {0};
4454 strcpy(buf, str);
4455 sprintf(str, "-%s", buf);
4456 INC_TF_CURSORS(d->d2,1,strlen(str));
4457 }
4458 }
4459 else if(!b && str[0] == '-')
4460 {
4461 char buf[16] = {0};
4462 strcpy(buf, str);
4463 sprintf(str, "%s", buf+1);
4464 INC_TF_CURSORS(d->d2,-1,strlen(str));
4465 }
4466 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4467 }
4468 if(v != b || msg == MSG_START)
4469 {
4470 switch(type)
4471 {
4472 case nswapDEC:
4473 if(b < 0)
4474 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4475 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4476 trim_trailing_0s(str);
4477 break;
4478 case nswapHEX:
4479 if(b<0)
4480 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4481 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4482 trim_trailing_0s(str);
4483 break;
4484 case nswapLDEC:
4485 sprintf(str, "%d", b);
4486 break;
4487 case nswapLHEX:
4488 if(b<0)
4489 sprintf(str, "-%X", -b);
4490 else sprintf(str, "%X", b);
4491 break;
4492 }
4493 d->d2 = 0xFFFF0000|strlen(str);
4494 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4495 }
4496 if(d->fg != b)
4497 {
4498 d->fg = b; //Store numeric data
4499 GUI_EVENT(d, geUPDATE_SWAP);
4500 }
4501 if(msg==MSG_CHAR && ((c&255)=='.'))
4502 {
4503 if(type >= nswapLDEC) //No '.' in long modes
4504 c&=~255;
4505 else
4506 {
4507 for(int32_t q = 0; str[q]; ++q)
4508 {
4509 if(str[q] == '.') //Only one '.'
4510 {
4511 c&=~255;
4512 break;
4513 }
4514 }
4515 }
4516 }
4517 bool rev_d2 = false;
4518 int32_t old_d2 = d->d2;
4519 int32_t ref_d2;
4520 if(msg == MSG_CHAR && queued_neg)
4521 {
4522 auto scursor = d->d2 & 0xFFFF;
4523 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4524 if(!scursor)
4525 {
4526 rev_d2 = true;
4527 INC_TF_CURSORS(d->d2,1,strlen(str));
4528 ref_d2 = d->d2;
4529 }
4530 }
4531 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4532 switch(type)
4533 {
4534 case nswapDEC:
4535 d->d1 = 12; //12 digits max (incl '-', '.')
4536 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4537 {
4538 int32_t p = 0;
4539 for(int32_t q = 0; str[q]; ++q)
4540 {
4541 if(str[q]=='.')
4542 {
4543 if((d->d2&0x0000FFFF) <= q)
4544 break; //typing before the '.'
4545 ++p;
4546 }
4547 else if(p) ++p;
4548 }
4549 if(p>=5) //too many chars after '.'
4550 c&=~255;
4551 }
4552 ret |= jwin_numedit_proc(msg, d, c);
4553 break;
4554 case nswapHEX:
4555 d->d1 = 11; //11 digits max (incl '-', '.')
4556 if(msg==MSG_CHAR && !editproc_special_key(c))
4557 {
4558 if(!((c&255)=='.'||isxdigit(c&255)))
4559 c&=~255;
4560 else if(isxdigit(c&255) && !isdigit(c&255))
4561 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4562 {
4563 if(str[q] == '.') //No hex digits to the right of the '.'
4564 {
4565 c&=~255;
4566 break;
4567 }
4568 }
4569 if((c&255) && !areaselect)
4570 {
4571 int32_t p = 0;
4572 for(int32_t q = 0; str[q]; ++q)
4573 {
4574 if(str[q]=='.')
4575 {
4576 if((d->d2&0x0000FFFF) <= q)
4577 break; //typing before the '.'
4578 ++p;
4579 }
4580 else if(p) ++p;
4581 }
4582 if(p>=5) //too many chars after '.'
4583 c&=~255;
4584 }
4585 if(isalpha(c&255)) //always capitalize
4586 c = (c&~255) | (toupper(c&255));
4587 }
4588 ret |= jwin_hexedit_proc(msg, d, c);
4589 break;
4590 case nswapLDEC:
4591 d->d1 = 11; //11 digits max (incl '-')
4592 ret |= jwin_numedit_proc(msg, d, c);
4593 break;
4594 case nswapLHEX:
4595 d->d1 = 9; //9 digits max (incl '-')
4596 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4597 c = (c&~255) | (toupper(c&255));
4598 ret |= jwin_hexedit_proc(msg, d, c);
4599 break;
4600 }
4601 if(rev_d2 && ref_d2 == d->d2)
4602 {
4603 d->d2 = old_d2;
4604 }
4605
4606 if(msg==MSG_START)
4607 tf_obj->refresh_cb_swap();
4608
4609 return ret;
4610 }
4611
4612 /* _calc_scroll_bar:
4613 * Helps find positions of buttons on the scroll bar.
4614 */
4615 void _calc_scroll_bar(int32_t h, int32_t height, int32_t listsize, int32_t offset,
4616 int32_t *bh, int32_t *len, int32_t *pos)
4617 {
4618 *bh = zc_max(zc_min((h-4)/2, 14), 0);
4619 *len = zc_max(((h - 32) * height + listsize/2) / listsize , 6);
4620 *pos = ((h - 32 - *len) * offset) / (listsize-height);
4621 }
4622
4623 /* _handle_scrollable_click:
4624 * Helper to process a click on a scrollable object.
4625 */
4626
4627 void _handle_jwin_scrollable_scroll_click(DIALOG *d, int32_t listsize, int32_t *offset, FONT *fnt)
4628 {
4629 enum { top_btn, bottom_btn, bar, top_bar, bottom_bar };
4630
4631 int32_t xx, yy;
4632 int32_t height = (d->h-3) / (fnt ? text_height(fnt) : 1);
4633 int32_t hh = d->h - 32;
4634 int32_t obj = bar;
4635 int32_t bh, len, pos;
4636 int32_t down = 1, last_draw = 0;
4637 int32_t redraw = 0, mouse_delay = 0;
4638
4639 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4640
4641 xx = d->x + d->w - 18;
4642
4643 // find out which object is being clicked
4644
4645 yy = gui_mouse_y();
4646
4647 if(yy <= d->y+2+bh)
4648 {
4649 obj = top_btn;
4650 yy = d->y+2;
4651 }
4652 else if(yy >= d->y+d->h-2-bh)
4653 {
4654 obj = bottom_btn;
4655 yy = d->y+d->h-2-bh;
4656 }
4657 else if(d->h > 32+6)
4658 {
4659 if(yy < d->y+2+bh+pos)
4660 obj = top_bar;
4661 else if(yy >= d->y+2+bh+pos+len)
4662 obj = bottom_bar;
4663 }
4664
4665 while(gui_mouse_b())
4666 {
4667 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4668
4669 switch(obj)
4670 {
4671 case top_btn:
4672 case bottom_btn:
4673 down = mouse_in_rect(xx, yy, 16, bh);
4674
4675 if(!down)
4676 mouse_delay = 0;
4677 else
4678 {
4679 if((mouse_delay&1)==0)
4680 {
4681 if(obj==top_btn && *offset>0)
4682 {
4683 (*offset)--;
4684 redraw = 1;
4685 }
4686
4687 if(obj==bottom_btn && *offset<listsize-height)
4688 {
4689 (*offset)++;
4690 redraw = 1;
4691 }
4692 }
4693
4694 mouse_delay++;
4695 }
4696
4697 if(down!=last_draw || redraw)
4698 {
4699 vsync();
4700 d->proc(MSG_DRAW, d, 0);
4701 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, down*3);
4702 last_draw = down;
4703 }
4704
4705 break;
4706
4707 case top_bar:
4708 case bottom_bar:
4709 if(mouse_in_rect(xx, d->y+2, 16, d->h-4))
4710 {
4711 if(obj==top_bar)
4712 {
4713 if(gui_mouse_y() < d->y+2+bh+pos)
4714 yy = *offset - height;
4715 }
4716 else
4717 {
4718 if(gui_mouse_y() >= d->y+2+bh+pos+len)
4719 yy = *offset + height;
4720 }
4721
4722 if(yy < 0)
4723 yy = 0;
4724
4725 if(yy > listsize-height)
4726 yy = listsize-height;
4727
4728 if(yy != *offset)
4729 {
4730 *offset = yy;
4731 vsync();
4732 d->proc(MSG_DRAW, d, 0);
4733 }
4734 }
4735
4736 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4737
4738 if(!mouse_in_rect(xx, d->y+2+bh+pos, 16, len))
4739 break;
4740
4741 // fall through
4742
4743 case bar:
4744 default:
4745 xx = gui_mouse_y() - pos;
4746
4747 while(gui_mouse_b())
4748 {
4749 yy = (listsize * (gui_mouse_y() - xx) + hh/2) / hh;
4750
4751 if(yy > listsize-height)
4752 yy = listsize-height;
4753
4754 if(yy < 0)
4755 yy = 0;
4756
4757 bool should_redraw = false;
4758 if(yy != *offset)
4759 {
4760 *offset = yy;
4761 d->proc(MSG_DRAW, d, 0);
4762 should_redraw = true;
4763 }
4764
4765 /* let other objects continue to animate */
4766 int r = broadcast_dialog_message(MSG_IDLE, 0);
4767 if (r & D_REDRAWME) should_redraw = true;
4768
4769 if (should_redraw)
4770 {
4771 update_hw_screen();
4772 }
4773 }
4774
4775 break;
4776
4777 } // switch(obj)
4778
4779 redraw = 0;
4780
4781 update_hw_screen();
4782 // let other objects continue to animate
4783 broadcast_dialog_message(MSG_IDLE, 0);
4784 }
4785
4786 if(last_draw==1)
4787 {
4788 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, 0);
4789 }
4790 }
4791
4792 /* _handle_scrollable_scroll:
4793 * Helper function to scroll through a scrollable object.
4794 */
4795
4796 static void _handle_jwin_scrollable_scroll(DIALOG *d, int32_t listsize, int32_t *index, int32_t *offset, FONT *fnt)
4797 {
4798 int32_t height = (d->h-3) / text_height(fnt);
4799
4800 if(listsize <= 0)
4801 {
4802 *index = *offset = 0;
4803 return;
4804 }
4805
4806 // check selected item
4807 if(*index < 0)
4808 *index = 0;
4809 else if(*index >= listsize)
4810 *index = listsize - 1;
4811
4812 // check scroll position
4813 while((*offset > 0) && (*offset + height > listsize))
4814 (*offset)--;
4815
4816 if(*offset >= *index)
4817 {
4818 if(*index < 0)
4819 *offset = 0;
4820 else
4821 *offset = *index;
4822 }
4823 else
4824 {
4825 while((*offset + height - 1) < *index)
4826 (*offset)++;
4827 }
4828 }
4829
4830 /* idle_cb:
4831 * rest_callback() routine to keep dialogs animating nice and smoothly.
4832 */
4833
4834 static void idle_cb()
4835 {
4836 broadcast_dialog_message(MSG_IDLE, 0);
4837 }
4838
4839 /* _handle_listbox_click:
4840 * Helper to process a click on a listbox, doing hit-testing and moving
4841 * the selection.
4842 */
4843
4844 static bool _handle_jwin_listbox_click(DIALOG *d)
4845 {
4846 ListData *data = (ListData *)d->dp;
4847 char *sel = (char *)d->dp2;
4848 int32_t listsize, height;
4849 int32_t i, j;
4850
4851 data->listFunc(-1, &listsize);
4852
4853 if(!listsize)
4854 return false;
4855
4856 height = (d->h-3) / text_height(*data->font);
4857
4858 i = MID(0, ((gui_mouse_y() - d->y - 4) / text_height(*data->font)),
4859 ((d->h-3) / text_height(*data->font) - 1));
4860 i += d->d2;
4861
4862 if(i < d->d2)
4863 i = d->d2;
4864 else
4865 {
4866 if(i > d->d2 + height-1)
4867 i = d->d2 + height-1;
4868
4869 if(i >= listsize)
4870 i = listsize-1;
4871 }
4872
4873 if(gui_mouse_y() <= d->y)
4874 i = MAX(i-1, 0);
4875 else if(gui_mouse_y() >= d->y+d->h)
4876 i = MIN(i+1, listsize-1);
4877
4878 if(i != d->d1)
4879 {
4880 if(sel)
4881 {
4882 if(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG))
4883 {
4884 if((key_shifts & KB_SHIFT_FLAG) || (d->flags & D_INTERNAL))
4885 {
4886 for(j=MIN(i, d->d1); j<=MAX(i, d->d1); j++)
4887 sel[j] = TRUE;
4888 }
4889 else
4890 sel[i] = TRUE;
4891 }
4892 }
4893
4894 d->d1 = i;
4895 i = d->d2;
4896
4897 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
4898
4899 object_message(d, MSG_DRAW, 0);
4900
4901 if(i != d->d2)
4902 rest_callback(MID(10, text_height(font)*16-d->h, 100), idle_cb);
4903 return true;
4904 }
4905 return false;
4906 }
4907
4908 /* _jwin_draw_scrollable_frame:
4909 * Helper function to draw a frame for all objects with vertical scrollbars.
4910 */
4911 void _jwin_draw_scrollable_frame(DIALOG *d, int32_t listsize, int32_t offset, int32_t height, int32_t type)
4912 {
4913 int32_t pos, len;
4914 int32_t xx, yy, hh, bh;
4915 static BITMAP *pattern = NULL; // just create it once
4916
4917 /* draw frame */
4918 if(type)
4919 // for droplists
4920 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DARK);
4921 else
4922 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
4923
4924 /* possibly draw scrollbar */
4925 if(listsize > height)
4926 {
4927 _calc_scroll_bar(d->h, height, listsize, offset, &bh, &len, &pos);
4928
4929 xx = d->x + d->w - 18;
4930
4931 draw_arrow_button(screen, xx, d->y+2, 16, bh, 1, 0);
4932 draw_arrow_button(screen, xx, d->y+d->h-2-bh, 16, bh, 0, 0);
4933
4934 if(d->h > 32)
4935 {
4936 yy = d->y + 16;
4937 hh = (d->h-32);
4938
4939 /* create and draw the scrollbar */
4940 if(!pattern)
4941 pattern = create_bitmap_ex(bitmap_color_depth(screen),2,2);
4942
4943 putpixel(pattern, 0, 1, scheme[jcLIGHT]);
4944 putpixel(pattern, 1, 0, scheme[jcLIGHT]);
4945 putpixel(pattern, 0, 0, scheme[jcBOX]);
4946 putpixel(pattern, 1, 1, scheme[jcBOX]);
4947
4948 drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0);
4949 rectfill(screen, xx, yy, xx+15, yy+hh-1, 0);
4950 solid_mode();
4951
4952 if(d->h > 32+6)
4953 {
4954 jwin_draw_button(screen, xx, yy+pos, 16, len, 0, 1);
4955 }
4956 }
4957
4958 if(d->flags & D_GOTFOCUS)
4959 _dotted_rect(d->x+2, d->y+2, d->x+d->w-19, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4960 }
4961 else if(d->flags & D_GOTFOCUS)
4962 _dotted_rect(d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4963 }
4964
4965 /*
4966 Effectively an overload of _jwin_draw_listbox that is used eclusively for file/abc listers.
4967 */
4968 void _jwin_draw_abclistbox(DIALOG *d)
4969 {
4970 int32_t height, listsize, i, len, bar, x, y, w;
4971 int32_t fg_color, bg_color, fg, bg;
4972 char *sel = (char*)d->dp2;
4973 char s[1024] = { 0 };
4974 ListData *data = (ListData *)d->dp;
4975
4976 FONT* oldfont = font;
4977 font = *data->font;
4978
4979 data->listFunc(-1, &listsize);
4980 height = (d->h-3) / text_height(font);
4981 bar = (listsize > height);
4982 w = (bar ? d->w-21 : d->w-5);
4983 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h+9, scheme[jcBOX]);
4984 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4985 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4986
4987 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4988 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4989 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4990 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4991 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4992 {
4993 rectfill(screen, d->x+1, d->y+d->h+2, d->x+d->w-2, d->y+1+d->h+text_height(font), bg_color);
4994 strncpy(s, abc_keypresses, 1023);
4995 char* s2 = s;
4996 int32_t tw = (d->w-1);
4997 while(text_length(font, s2) >= tw)
4998 {
4999 ++s2;
5000 }
5001 textout_ex(screen, font, s2, d->x+1, d->y+d->h+2,fg_color, bg_color);
5002 }
5003 //d->flags|=D_DIRTY;
5004
5005 /* draw box contents */
5006 for(i=0; i<height; i++)
5007 {
5008 if(d->d2+i < listsize)
5009 {
5010 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
5011 {
5012 fg = scheme[jcSELFG];
5013 bg = scheme[jcSELBG];
5014 }
5015 else if((sel) && (sel[d->d2+i]))
5016 {
5017 fg = scheme[jcDISABLED_FG];
5018 bg = scheme[jcSELBG];
5019 }
5020 else
5021 {
5022 fg = fg_color;
5023 bg = bg_color;
5024 }
5025
5026 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
5027 x = d->x + 4;
5028 y = d->y + 4 + i*text_height(*data->font);
5029 // text_mode(bg);
5030 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
5031 x += 8;
5032 len = (int32_t)strlen(s);
5033
5034 while(text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
5035 {
5036 len--;
5037 s[len] = 0;
5038 }
5039
5040 textout_ex(screen, *data->font, s, x, y, fg,bg);
5041 x += text_length(*data->font, s);
5042
5043 if(x <= d->x+w)
5044 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
5045 }
5046 else
5047 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5048 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
5049 }
5050
5051 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
5052 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5053 d->x+w+2, d->y+d->h-3, bg_color);
5054
5055 /* draw frame, maybe with scrollbar */
5056 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
5057
5058 font = oldfont;
5059 }
5060
5061 /* _jwin_draw_listbox:
5062 * Helper function to draw a listbox object.
5063 */
5064 void _jwin_draw_listbox(DIALOG *d)
5065 {
5066 int32_t height, listsize, i, len, bar, x, y, w;
5067 int32_t fg_color, bg_color, fg, bg;
5068 char *sel = (char*)d->dp2;
5069 char s[1024] = {0};
5070 ListData *data = (ListData *)d->dp;
5071
5072 data->listFunc(-1, &listsize);
5073 height = (d->h-3) / text_height(*data->font);
5074 bar = (listsize > height);
5075 w = (bar ? d->w-21 : d->w-5);
5076 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
5077 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
5078
5079 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
5080 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
5081 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
5082 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
5083 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
5084
5085 /* draw box contents */
5086 for(i=0; i<height; i++)
5087 {
5088 if(d->d2+i < listsize)
5089 {
5090 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
5091 {
5092 fg = scheme[jcSELFG];
5093 bg = scheme[jcSELBG];
5094 }
5095 else if((sel) && (sel[d->d2+i]))
5096 {
5097 fg = scheme[jcMEDDARK];
5098 bg = scheme[jcSELBG];
5099 }
5100 else
5101 {
5102 fg = fg_color;
5103 bg = bg_color;
5104 }
5105
5106 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
5107 x = d->x + 4;
5108 y = d->y + 4 + i*text_height(*data->font);
5109 // text_mode(bg);
5110 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
5111 x += 8;
5112 len = (int32_t)strlen(s);
5113
5114 while(len > 0 && text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
5115 {
5116 len--;
5117 s[len] = 0;
5118 }
5119
5120 textout_ex(screen, *data->font, s, x, y, fg,bg);
5121 x += text_length(*data->font, s);
5122
5123 if(x <= d->x+w)
5124 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
5125 }
5126 else
5127 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5128 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
5129 }
5130
5131 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
5132 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5133 d->x+w+2, d->y+d->h-3, bg_color);
5134
5135 /* draw frame, maybe with scrollbar */
5136 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
5137 }
5138
5139 /* jwin_list_proc:
5140 * A list box object. The dp field points to a ListData struct containing
5141 * a function which it will call
5142 * to obtain information about the list. This should follow the form:
5143 * char *<list_func_name> (int32_t index, int32_t *list_size);
5144 * If index is zero or positive, the function should return a pointer to
5145 * the string which is to be displayed at position index in the list. If
5146 * index is negative, it should return null and list_size should be set
5147 * to the number of items in the list. The list box object will allow the
5148 * user to scroll through the list and to select items list by clicking
5149 * on them, and if it has the input focus also by using the arrow keys. If
5150 * the D_EXIT flag is set, double clicking on a list item will cause it to
5151 * close the dialog. The index of the selected item is held in the d1
5152 * field, and d2 is used to store how far it has scrolled through the list.
5153 */
5154 int32_t jwin_list_proc(int32_t msg, DIALOG *d, int32_t c)
5155 {
5156 ListData *data = (ListData *)d->dp;
5157 int32_t listsize, i, bottom, height, bar, orig;
5158 char *sel = (char *)d->dp2;
5159 int32_t redraw = FALSE;
5160
5161 switch(msg)
5162 {
5163
5164 case MSG_START:
5165 data->listFunc(-1, &listsize);
5166 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5167 break;
5168
5169 case MSG_DRAW:
5170 _jwin_draw_listbox(d);
5171 break;
5172
5173 case MSG_CLICK:
5174 data->listFunc(-1, &listsize);
5175 height = (d->h-3) / text_height(*data->font);
5176 bar = (listsize > height);
5177
5178 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5179 {
5180 if((sel) && (!(key_shifts & KB_CTRL_CMD_FLAG)))
5181 {
5182 for(i=0; i<listsize; i++)
5183 {
5184 if(sel[i])
5185 {
5186 redraw = TRUE;
5187 sel[i] = FALSE;
5188 }
5189 }
5190
5191 if(redraw)
5192 {
5193 object_message(d, MSG_DRAW, 0);
5194 }
5195 }
5196
5197 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5198
5199 bool rightClicked=(gui_mouse_b()&2)!=0;
5200 while(gui_mouse_b())
5201 {
5202 broadcast_dialog_message(MSG_IDLE, 0);
5203 d->flags |= D_INTERNAL;
5204 bool should_redraw = false;
5205 if(_handle_jwin_listbox_click(d))
5206 {
5207 d->flags &= ~D_INTERNAL;
5208 GUI_EVENT(d, geCHANGE_SELECTION);
5209 should_redraw = true;
5210 }
5211 d->flags &= ~D_INTERNAL;
5212
5213 /* let other objects continue to animate */
5214 int r = broadcast_dialog_message(MSG_IDLE, 0);
5215 if (r & D_REDRAWME) should_redraw = true;
5216
5217 if (should_redraw)
5218 {
5219 update_hw_screen();
5220 }
5221 }
5222
5223 if(rightClicked)
5224 {
5225 GUI_EVENT(d, geRCLICK);
5226 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5227 {
5228 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5229 funcType func=reinterpret_cast<funcType>(d->dp3);
5230 func(d->d1, gui_mouse_x(), gui_mouse_y());
5231 }
5232 }
5233
5234 if(d->flags & D_USER)
5235 {
5236 if(listsize)
5237 {
5238 clear_keybuf();
5239 return D_CLOSE;
5240 }
5241 }
5242
5243 return D_REDRAWME;
5244 }
5245 else
5246 {
5247 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5248 }
5249
5250 break;
5251
5252 case MSG_DCLICK:
5253 // Ignore double right-click
5254 if((gui_mouse_b()&2)!=0)
5255 break;
5256
5257 data->listFunc(-1, &listsize);
5258 height = (d->h-3) / text_height(*data->font);
5259 bar = (listsize > height);
5260
5261 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5262 {
5263 if(listsize)
5264 {
5265 i = d->d1;
5266 object_message(d, MSG_CLICK, 0);
5267
5268 if(i == d->d1)
5269 {
5270 if(d->flags & D_EXIT)
5271 return D_CLOSE;
5272 else GUI_EVENT(d, geDCLICK);
5273 }
5274 }
5275 }
5276
5277 break;
5278
5279 case MSG_KEY:
5280 data->listFunc(-1, &listsize);
5281
5282 if((listsize) && (d->flags & D_EXIT))
5283 return D_CLOSE;
5284
5285 break;
5286
5287 case MSG_WANTFOCUS:
5288 return D_WANTFOCUS;
5289
5290 case MSG_WANTWHEEL:
5291 return 1;
5292
5293 case MSG_WHEEL:
5294 data->listFunc(-1, &listsize);
5295 height = (d->h-4) / text_height(*data->font);
5296
5297 if(height < listsize)
5298 {
5299 int32_t delta = (height > 3) ? 3 : 1;
5300
5301 if(c > 0)
5302 {
5303 i = MAX(0, d->d2-delta);
5304 }
5305 else
5306 {
5307 i = MIN(listsize-height, d->d2+delta);
5308 }
5309
5310 if(i != d->d2)
5311 {
5312 d->d2 = i;
5313 object_message(d, MSG_DRAW, 0);
5314 GUI_EVENT(d, geCHANGE_SELECTION);
5315 return D_REDRAWME;
5316 }
5317 }
5318
5319 break;
5320
5321 case MSG_CHAR:
5322 data->listFunc(-1,&listsize);
5323
5324 if(listsize)
5325 {
5326 c >>= 8;
5327
5328 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5329
5330 if(bottom >= listsize-1)
5331 bottom = listsize-1;
5332
5333 orig = d->d1;
5334
5335 if(c == KEY_UP)
5336 d->d1--;
5337 else if(c == KEY_DOWN)
5338 d->d1++;
5339 else if(c == KEY_HOME)
5340 d->d1 = 0;
5341 else if(c == KEY_END)
5342 d->d1 = listsize-1;
5343 else if(c == KEY_PGUP)
5344 {
5345 if(d->d1 > d->d2)
5346 d->d1 = d->d2;
5347 else
5348 d->d1 -= (bottom - d->d2);
5349 }
5350 else if(c == KEY_PGDN)
5351 {
5352 if(d->d1 < bottom)
5353 d->d1 = bottom;
5354 else
5355 d->d1 += (bottom - d->d2);
5356 }
5357 else
5358 return D_O_K;
5359
5360 if(sel)
5361 {
5362 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG)))
5363 {
5364 for(i=0; i<listsize; i++)
5365 sel[i] = FALSE;
5366 }
5367 else if(key_shifts & KB_SHIFT_FLAG)
5368 {
5369 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5370 {
5371 if(key_shifts & KB_CTRL_CMD_FLAG)
5372 sel[i] = (i != d->d1);
5373 else
5374 sel[i] = TRUE;
5375 }
5376 }
5377 }
5378
5379 /* if we changed something, better redraw... !Also bounds the index! */
5380 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5381
5382 GUI_EVENT(d, geCHANGE_SELECTION);
5383
5384 if (d->d1 != orig)
5385 d->flags |= D_DIRTY;
5386 return D_USED_CHAR;
5387 }
5388
5389 break;
5390 }
5391
5392 return D_O_K;
5393 }
5394
5395
5396 /*
5397 Effectively an overload of jwin_list_proc that i used eclusively for abc lists.
5398 This calls the appropriate form of drawing for those listers.
5399 */
5400 int32_t jwin_do_abclist_proc(int32_t msg, DIALOG *d, int32_t c)
5401 {
5402 ListData *data = (ListData *)d->dp;
5403 int32_t listsize, i, bottom, height, bar, orig, h;
5404 int32_t ret = D_O_K;
5405 bool revert_size = false;
5406 if((d->flags & D_RESIZED) == 0)
5407 {
5408 h = d->h;
5409 d->h -= text_height(*data->font);
5410 d->flags |= D_RESIZED;
5411 revert_size = true;
5412 }
5413 char *sel = (char *)d->dp2;
5414 int32_t redraw = FALSE;
5415
5416 switch(msg)
5417 {
5418
5419 case MSG_START:
5420 data->listFunc(-1, &listsize);
5421 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5422 break;
5423
5424 case MSG_DRAW:
5425 _jwin_draw_abclistbox(d);
5426 break;
5427
5428 case MSG_CLICK:
5429 if(gui_mouse_y() > (d->y+d->h-1))
5430 {
5431 if(gui_mouse_y() > (d->y+d->h+2))
5432 {
5433 //Clicked on the box displaying the patternmatch
5434 }
5435 else {} //Clicked between the lister and patternmatch
5436 }
5437 else //Clicked the lister
5438 {
5439 data->listFunc(-1, &listsize);
5440 height = (d->h-3) / text_height(*data->font);
5441 bar = (listsize > height);
5442
5443 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5444 {
5445 if((sel) && (!(key_shifts & KB_CTRL_CMD_FLAG)))
5446 {
5447 for(i=0; i<listsize; i++)
5448 {
5449 if(sel[i])
5450 {
5451 redraw = TRUE;
5452 sel[i] = FALSE;
5453 }
5454 }
5455
5456 if(redraw)
5457 {
5458 object_message(d, MSG_DRAW, 0);
5459 }
5460 }
5461
5462 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5463
5464 bool rightClicked=(gui_mouse_b()&2)!=0;
5465 while(gui_mouse_b())
5466 {
5467 broadcast_dialog_message(MSG_IDLE, 0);
5468 d->flags |= D_INTERNAL;
5469 if(_handle_jwin_listbox_click(d))
5470 {
5471 d->flags &= ~D_INTERNAL;
5472 GUI_EVENT(d, geCHANGE_SELECTION);
5473 update_hw_screen();
5474 }
5475 d->flags &= ~D_INTERNAL;
5476 rest(1);
5477 }
5478
5479 if(rightClicked)
5480 {
5481 GUI_EVENT(d, geRCLICK);
5482 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5483 {
5484 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5485 funcType func=reinterpret_cast<funcType>(d->dp3);
5486 func(d->d1, gui_mouse_x(), gui_mouse_y());
5487 }
5488 }
5489
5490 if(d->flags & D_USER)
5491 {
5492 if(listsize)
5493 {
5494 clear_keybuf();
5495 ret = D_CLOSE;
5496 }
5497 }
5498
5499 return D_REDRAWME;
5500 }
5501 else
5502 {
5503 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5504 }
5505 }
5506 break;
5507
5508 case MSG_DCLICK:
5509 // Ignore double right-click
5510 if((gui_mouse_b()&2)!=0)
5511 break;
5512
5513 if(gui_mouse_y() > (d->y+d->h-1))
5514 {
5515 if(gui_mouse_y() > (d->y+d->h+2))
5516 {
5517 //Clicked on the box displaying the patternmatch
5518 }
5519 else {} //Clicked between the lister and patternmatch
5520 }
5521 else //Clicked the lister
5522 {
5523 data->listFunc(-1, &listsize);
5524 height = (d->h-3) / text_height(*data->font);
5525 bar = (listsize > height);
5526
5527 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5528 {
5529 if(listsize)
5530 {
5531 i = d->d1;
5532 object_message(d, MSG_CLICK, 0);
5533
5534 if(i == d->d1)
5535 {
5536 if(d->flags & D_EXIT)
5537 ret = D_CLOSE;
5538 else GUI_EVENT(d, geDCLICK);
5539 }
5540 }
5541 }
5542 }
5543 break;
5544
5545 case MSG_KEY:
5546 data->listFunc(-1, &listsize);
5547
5548 if((listsize) && (d->flags & D_EXIT))
5549 ret = D_CLOSE;
5550
5551 break;
5552
5553 case MSG_WANTFOCUS:
5554 ret = D_WANTFOCUS;
5555 break;
5556
5557 case MSG_WANTWHEEL:
5558 return 1;
5559
5560 case MSG_WHEEL:
5561 data->listFunc(-1, &listsize);
5562 height = (d->h-4) / text_height(*data->font);
5563
5564 if(height < listsize)
5565 {
5566 int32_t delta = (height > 3) ? 3 : 1;
5567
5568 if(c > 0)
5569 {
5570 i = MAX(0, d->d2-delta);
5571 }
5572 else
5573 {
5574 i = MIN(listsize-height, d->d2+delta);
5575 }
5576
5577 if(i != d->d2)
5578 {
5579 d->d2 = i;
5580 object_message(d, MSG_DRAW, 0);
5581 GUI_EVENT(d, geCHANGE_SELECTION);
5582 ret |= D_REDRAWME;
5583 }
5584 }
5585
5586 break;
5587
5588 case MSG_CHAR:
5589 data->listFunc(-1,&listsize);
5590
5591 if(listsize)
5592 {
5593 c >>= 8;
5594
5595 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5596
5597 if(bottom >= listsize-1)
5598 bottom = listsize-1;
5599
5600 orig = d->d1;
5601
5602 if(c == KEY_UP)
5603 d->d1--;
5604 else if(c == KEY_DOWN)
5605 d->d1++;
5606 else if(c == KEY_HOME)
5607 d->d1 = 0;
5608 else if(c == KEY_END)
5609 d->d1 = listsize-1;
5610 else if(c == KEY_PGUP)
5611 {
5612 if(d->d1 > d->d2)
5613 d->d1 = d->d2;
5614 else
5615 d->d1 -= (bottom - d->d2);
5616 }
5617 else if(c == KEY_PGDN)
5618 {
5619 if(d->d1 < bottom)
5620 d->d1 = bottom;
5621 else
5622 d->d1 += (bottom - d->d2);
5623 }
5624 else
5625 break; //return D_O_K;
5626
5627 if(sel)
5628 {
5629 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG)))
5630 {
5631 for(i=0; i<listsize; i++)
5632 sel[i] = FALSE;
5633 }
5634 else if(key_shifts & KB_SHIFT_FLAG)
5635 {
5636 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5637 {
5638 if(key_shifts & KB_CTRL_CMD_FLAG)
5639 sel[i] = (i != d->d1);
5640 else
5641 sel[i] = TRUE;
5642 }
5643 }
5644 }
5645
5646 /* if we changed something, better redraw... */
5647 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5648
5649 GUI_EVENT(d, geCHANGE_SELECTION);
5650
5651 if (d->d1 != orig)
5652 d->flags |= D_DIRTY;
5653 ret = D_USED_CHAR;
5654 }
5655
5656 break;
5657 }
5658 if(revert_size)
5659 {
5660 d->h = h;
5661 d->flags &= ~D_RESIZED;
5662 }
5663 return ret;
5664 }
5665
5666 /* _jwin_draw_textbox:
5667 * Helper function to draw a textbox object.
5668 */
5669 void _jwin_draw_textbox(char *thetext, int32_t *listsize, int32_t draw, int32_t offset,
5670 int32_t wword, int32_t tabsize, int32_t x, int32_t y, int32_t w, int32_t h,
5671 int32_t disabled)
5672 {
5673 int32_t fg = scheme[jcTEXTFG];
5674 int32_t bg = scheme[jcTEXTBG];
5675 int32_t y1 = y+4;
5676 int32_t x1;
5677 int32_t len;
5678 int32_t ww = w-10;
5679 char s[16] = {0};
5680 char text[16] = {0};
5681 char space[16] = {0};
5682 char *printed = text;
5683 char *scanned = text;
5684 char *oldscan = text;
5685 char *ignore = NULL;
5686 char *tmp, *ptmp;
5687 int32_t width;
5688 int32_t line = 0;
5689 int32_t i = 0;
5690 int32_t noignore;
5691 // int32_t rtm;
5692
5693 usetc(s+usetc(s, '.'), 0);
5694 usetc(text+usetc(text, ' '), 0);
5695 usetc(space+usetc(space, ' '), 0);
5696
5697 /* find the correct text */
5698 if(thetext != NULL)
5699 {
5700 printed = thetext;
5701 scanned = thetext;
5702 }
5703
5704 /* choose the text color */
5705 if(disabled)
5706 {
5707 fg = scheme[jcDISABLED_FG];
5708 bg = scheme[jcDISABLED_BG];
5709 }
5710
5711 /* do some drawing setup */
5712 if(draw)
5713 {
5714 /* initial start blanking at the top */
5715 rectfill(screen, x+2, y+2, x+w-2, y1-1, bg);
5716 }
5717
5718 // rtm = text_mode(bg);
5719
5720 /* loop over the entire string */
5721 for(;;)
5722 {
5723 width = 0;
5724
5725 /* find the next break */
5726 while(ugetc(scanned))
5727 {
5728 /* check for a forced break */
5729 if(ugetc(scanned) == '\n')
5730 {
5731 scanned += uwidth(scanned);
5732
5733 /* we are done parsing the line end */
5734 break;
5735 }
5736
5737 /* the next character length */
5738 usetc(s+usetc(s, ugetc(scanned)), 0);
5739 len = text_length(font, s);
5740
5741 /* modify length if its a tab */
5742 if(ugetc(s) == '\t')
5743 len = tabsize * text_length(font, space);
5744
5745 /* check for the end of a line by excess width of next char */
5746 if(width+len >= ww)
5747 {
5748 /* we have reached end of line do we go back to find start */
5749 if(wword)
5750 {
5751 /* remember where we were */
5752 oldscan = scanned;
5753 noignore = FALSE;
5754
5755 /* go backwards looking for start of word */
5756 while(!uisspace(ugetc(scanned)))
5757 {
5758 /* don't wrap too far */
5759 if(scanned == printed)
5760 {
5761 /* the whole line is filled, so stop here */
5762 tmp = ptmp = scanned;
5763
5764 while(ptmp != oldscan)
5765 {
5766 ptmp = tmp;
5767 tmp += uwidth(tmp);
5768 }
5769
5770 scanned = ptmp;
5771 noignore = TRUE;
5772 break;
5773 }
5774
5775 /* look further backwards to wrap */
5776 tmp = ptmp = printed;
5777
5778 while(tmp < scanned)
5779 {
5780 ptmp = tmp;
5781 tmp += uwidth(tmp);
5782 }
5783
5784 scanned = ptmp;
5785 }
5786
5787 /* put the space at the end of the line */
5788 if(!noignore)
5789 {
5790 ignore = scanned;
5791 scanned += uwidth(scanned);
5792 }
5793 else
5794 ignore = NULL;
5795
5796 /* check for endline at the convenient place */
5797 if(ugetc(scanned) == '\n')
5798 scanned += uwidth(scanned);
5799 }
5800
5801 /* we are done parsing the line end */
5802 break;
5803 }
5804
5805 /* the character can be added */
5806 scanned += uwidth(scanned);
5807 width += len;
5808 }
5809
5810 /* check if we are to print it */
5811 if((draw) && (line >= offset) && (y1+text_height(font) < (y+h-3)))
5812 {
5813 x1 = x+4;
5814
5815 /* the initial blank bit */
5816 rectfill(screen, x+2, y1, x1-1, y1+text_height(font), bg);
5817
5818 /* print up to the marked character */
5819 while(printed != scanned)
5820 {
5821 /* do special stuff for each character */
5822 switch(ugetc(printed))
5823 {
5824
5825 case '\r':
5826 case '\n':
5827 /* don't print endlines in the text */
5828 break;
5829
5830 /* possibly expand the tabs */
5831 case '\t':
5832 for(i=0; i<tabsize; i++)
5833 {
5834 usetc(s+usetc(s, ' '), 0);
5835 textout_ex(screen, font, s, x1, y1, fg,bg);
5836 x1 += text_length(font, s);
5837 }
5838
5839 break;
5840
5841 /* print a normal character */
5842 default:
5843 if(printed != ignore)
5844 {
5845 usetc(s+usetc(s, ugetc(printed)), 0);
5846 textout_ex(screen, font, s, x1, y1, fg,bg);
5847 x1 += text_length(font, s);
5848 }
5849 }
5850
5851 /* goto the next character */
5852 printed += uwidth(printed);
5853 }
5854
5855 /* the last blank bit */
5856 if(x1 <= x+w-3)
5857 rectfill(screen, x1, y1, x+w-2, y1+text_height(font)-1, bg);
5858
5859 /* print the line end */
5860 y1 += text_height(font);
5861 }
5862
5863 printed = scanned;
5864
5865 /* we have done a line */
5866 line++;
5867
5868 /* check if we are at the end of the string */
5869 if(!ugetc(printed))
5870 {
5871 /* the under blank bit */
5872 if(draw)
5873 rectfill(screen, x+1, y1, x+w-2, y+h-1, bg);
5874
5875 /* tell how many lines we found */
5876 *listsize = line;
5877 // text_mode(rtm);
5878 return;
5879 }
5880 }
5881
5882 // text_mode(rtm);
5883 }
5884
5885 /* jwin_textbox_proc:
5886 * A text box object. The dp field points to a char * which is the text
5887 * to be displayed in the text box. If the text is long, there will be
5888 * a vertical scrollbar on the right hand side of the object which can
5889 * be used to scroll through the text. The default is to print the text
5890 * with word wrapping, but if the D_SELECTED flag is set, the text will
5891 * be printed with character wrapping. The d1 field is used internally
5892 * to store the number of lines of text, and d2 is used to store how far
5893 * it has scrolled through the text.
5894 */
5895 int32_t jwin_textbox_proc(int32_t msg, DIALOG *d, int32_t c)
5896 {
5897 int32_t height, bar, ret = D_O_K;
5898 int32_t start, top, bottom,l;
5899 int32_t used, delta;
5900 // int32_t fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
5901
5902 FONT *oldfont=NULL;
5903
5904 if(d->dp2!=NULL)
5905 {
5906 oldfont=font;
5907 font=(FONT*)d->dp2;
5908 }
5909
5910 /* calculate the actual height */
5911 height = (d->h-4) / text_height(font);
5912
5913 switch(msg)
5914 {
5915
5916 case MSG_START:
5917 /* measure how many lines of text we contain */
5918 _jwin_draw_textbox((char*)d->dp, &d->d1,
5919 0, /* DONT DRAW anything */
5920 d->d2, !(d->flags & D_SELECTED), 8,
5921 d->x, d->y, d->w, d->h,
5922 (d->flags & D_DISABLED));
5923 break;
5924
5925 case MSG_DRAW:
5926 /* tell the object to sort of draw, but only calculate the listsize */
5927 _jwin_draw_textbox((char*)d->dp, &d->d1,
5928 0, /* DONT DRAW anything */
5929 d->d2, !(d->flags & D_SELECTED), 8,
5930 d->x, d->y, d->w, d->h,
5931 (d->flags & D_DISABLED));
5932
5933 if(d->d1 > height)
5934 {
5935 bar = 16;
5936 }
5937 else
5938 {
5939 bar = 0;
5940 d->d2 = 0;
5941 }
5942
5943 /* now do the actual drawing */
5944 _jwin_draw_textbox((char*)d->dp, &d->d1, 1, d->d2,
5945 !(d->flags & D_SELECTED), 8,
5946 d->x, d->y, d->w-bar-1, d->h,
5947 (d->flags & D_DISABLED));
5948
5949 /* draw the frame around */
5950 _jwin_draw_scrollable_frame(d, d->d1, d->d2, height, 0);
5951 break;
5952
5953 case MSG_CLICK:
5954 /* figure out if it's on the text or the scrollbar */
5955 bar = (d->d1 > height);
5956
5957 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5958 {
5959 /* clicked on the text area */
5960 ret = D_O_K;
5961 }
5962 else
5963 {
5964 /* clicked on the scroll area */
5965 _handle_jwin_scrollable_scroll_click(d, d->d1, &d->d2, font);
5966 }
5967
5968 break;
5969
5970 case MSG_WANTWHEEL:
5971 return 1;
5972
5973 case MSG_WHEEL:
5974 l = (d->h-8)/text_height(font);
5975 delta = (l > 3) ? 3 : 1;
5976
5977 // scroll, making sure that the list stays in bounds
5978 start = d->d2;
5979 d->d2 = (c > 0) ? MAX(0, d->d2-delta) : MIN(d->d1-l, d->d2+delta);
5980
5981 // if we changed something, better redraw...
5982 if(d->d2 != start)
5983 {
5984 d->flags |= D_DIRTY;
5985 }
5986
5987 ret = D_O_K;
5988 break;
5989
5990 case MSG_CHAR:
5991 start = d->d2;
5992 used = D_USED_CHAR;
5993
5994 if(d->d1 > 0)
5995 {
5996 if(d->d2 > 0)
5997 top = d->d2+1;
5998 else
5999 top = 0;
6000
6001 l = (d->h-3)/text_height(font);
6002
6003 bottom = d->d2 + l - 1;
6004
6005 if(bottom >= d->d1-1)
6006 bottom = d->d1-1;
6007 else
6008 bottom--;
6009
6010 if((c>>8) == KEY_UP)
6011 d->d2--;
6012 else if((c>>8) == KEY_DOWN)
6013 d->d2++;
6014 else if((c>>8) == KEY_HOME)
6015 d->d2 = 0;
6016 else if((c>>8) == KEY_END)
6017 d->d2 = d->d1-l;
6018 else if((c>>8) == KEY_PGUP)
6019 d->d2 = d->d2-(bottom-top);
6020 else if((c>>8) == KEY_PGDN)
6021 d->d2 = d->d2+(bottom-top);
6022 else
6023 used = D_O_K;
6024
6025 /* make sure that the list stays in bounds */
6026 if(d->d2 > d->d1-l)
6027 d->d2 = d->d1-l;
6028
6029 if(d->d2 < 0)
6030 d->d2 = 0;
6031 }
6032 else
6033 used = D_O_K;
6034
6035 /* if we changed something, better redraw... */
6036 if(d->d2 != start)
6037 {
6038 d->proc(MSG_DRAW, d, 0);
6039 }
6040
6041 ret = used;
6042 break;
6043
6044 case MSG_WANTFOCUS:
6045
6046 /* if we don't have a scrollbar we can't do anything with the focus */
6047 if(d->d1 > height)
6048 ret = D_WANTFOCUS;
6049
6050 break;
6051
6052 default:
6053 ret = D_O_K;
6054 }
6055
6056 if(d->dp2!=NULL)
6057 {
6058 font=oldfont;
6059 }
6060
6061 return ret;
6062 }
6063
6064 /* jwin_slider_proc:
6065 * A slider control object. This object returns a value in d2, in the
6066 * range from 0 to d1. It will display as a vertical slider if h is
6067 * greater than or equal to w; otherwise, it will display as a horizontal
6068 * slider. dp can contain an optional bitmap to use for the slider handle;
6069 * dp2 can contain an optional callback function, which is called each
6070 * time d2 changes. The callback function should have the following
6071 * prototype:
6072 *
6073 * int32_t function(void *dp3, int32_t d2);
6074 *
6075 * The d_slider_proc object will return the value of the callback function.
6076 */
6077 int32_t jwin_slider_proc(int32_t msg, DIALOG *d, int32_t c)
6078 {
6079 BITMAP *slhan = NULL;
6080 int32_t sfg; /* slider foreground color */
6081 int32_t vert = TRUE; /* flag: is slider vertical? */
6082 int32_t hh = 7; /* handle height (width for horizontal sliders) */
6083 int32_t hmar; /* handle margin */
6084 int32_t slp; /* slider position */
6085 int32_t irange;
6086 int32_t slx, sly, slh, slw;
6087 fixed slratio, slmax, slpos;
6088 ASSERT(d);
6089
6090 /* check for slider direction */
6091 if(d->h < d->w)
6092 {
6093 vert = FALSE;
6094 }
6095
6096 /* set up the metrics for the control */
6097 if(d->dp != NULL)
6098 {
6099 slhan = (BITMAP *)d->dp;
6100
6101 if(vert)
6102 {
6103 hh = slhan->h;
6104 }
6105 else
6106 {
6107 hh = slhan->w;
6108 }
6109 }
6110
6111 hmar = hh/2;
6112 irange = (vert) ? d->h : d->w;
6113 slmax = itofix(irange-hh);
6114 slratio = slmax / (d->d1);
6115 slpos = slratio * d->d2;
6116 slp = fixtoi(slpos);
6117
6118 switch(msg)
6119 {
6120 case MSG_DRAW:
6121 // sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6122 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6123
6124 if(vert)
6125 {
6126 rectfill(screen, d->x, d->y, d->x+d->w/2-2, d->y+d->h, scheme[jcBOX]);
6127 rectfill(screen, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h, sfg);
6128 rectfill(screen, d->x+d->w/2+2, d->y, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6129 }
6130 else
6131 {
6132 rectfill(screen, d->x, d->y, d->x+d->w, d->y+d->h/2-2, scheme[jcBOX]);
6133 rectfill(screen, d->x, d->y+d->h/2-1, d->x+d->w, d->y+d->h/2+1, sfg);
6134 rectfill(screen, d->x, d->y+d->h/2+2, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6135 }
6136
6137 if(d->flags & D_GOTFOCUS)
6138 {
6139 _dotted_rect(d->x, d->y, d->x+d->w, d->y+d->h, sfg, scheme[jcBOX]);
6140 }
6141
6142 /* okay, background and slot are drawn, now draw the handle */
6143 if(slhan)
6144 {
6145 if(vert)
6146 {
6147 slx = d->x+(d->w/2)-(slhan->w/2);
6148 sly = d->y+d->h-(hh+slp);
6149 }
6150 else
6151 {
6152 slx = d->x+slp;
6153 sly = d->y+(d->h/2)-(slhan->h/2);
6154 }
6155
6156 draw_sprite(screen, slhan, slx, sly);
6157 }
6158 else
6159 {
6160 /* draw default handle */
6161 if(vert)
6162 {
6163 slx = d->x;
6164 sly = d->y+d->h-(hh+slp);
6165 slw = d->w;
6166 slh = hh;
6167 }
6168 else
6169 {
6170 slx = d->x+slp;
6171 sly = d->y;
6172 slw = hh;
6173 slh = d->h;
6174 }
6175
6176 jwin_draw_button(screen, slx, sly, slw+1, slh+1, d->flags&D_DISABLED?3:0, 0);
6177 }
6178
6179 break;
6180
6181 default:
6182 return d_jslider_proc(msg, d, c);
6183 }
6184
6185 return D_O_K;
6186 }
6187
6188 const char* rowpref(int32_t row, bool alt)
6189 {
6190 static const char *lcol = "Level Colors", *syscol = "System Colors", *bosscol = "Boss Colors", *thmcol = "Theme Colors", *nlcol="";
6191 switch(row)
6192 {
6193 case 2: case 3: case 4: case 9:
6194 return lcol;
6195 case 14:
6196 return alt ? syscol : bosscol;
6197 case 15:
6198 return thmcol;
6199 default:
6200 return nlcol;
6201 }
6202 }
6203
6204 byte getHighlightColor(int32_t c)
6205 {
6206 RGB col;
6207 get_color(c, &col);
6208 return getHighlightColor(col);
6209 }
6210
6211 byte getHighlightColor(RGB const& col)
6212 {
6213 double lum = (pow(col.r/64.0, 2.2) * 0.2126) +
6214 (pow(col.g/64.0, 2.2) * 0.7152) +
6215 (pow(col.b/64.0, 2.2) * 0.0722);
6216 return lum < 0.4 ? vc(15) : vc(0);
6217 //Old -Em
6218 // byte bright = (col.r >= 32) + (col.g >= 32) + (col.b >= 32);
6219 // byte sbright = (col.r >= 48) + (col.g >= 48) + (col.b >= 48);
6220 // byte highlightColor = vc(7); //sysgray
6221 // if(bright >= 2)
6222 // {
6223 // if(sbright >= 2)
6224 // highlightColor = vc(0); //sysblack
6225 // else highlightColor = vc(8); //sysdarkgray
6226 // }
6227 // else if(!bright)
6228 // highlightColor = vc(15); //syswhite
6229 // return highlightColor;
6230 }
6231
6232 int32_t jwin_selcolor_proc(int32_t msg, DIALOG *d, int32_t c)
6233 {
6234 int32_t ret = D_O_K;
6235 if(!d->d2) d->d2 = 12;
6236 bool alt = d->d2 > 16;
6237 int32_t numcsets = alt ? 16 : d->d2;
6238 int32_t numcol = numcsets*0x10;
6239 if(msg==MSG_START)
6240 {
6241 d->w = d->h = (16*8) * 1.5;
6242 }
6243 int32_t csz = 12;
6244 d->w = csz * 16;
6245 d->h = csz * numcsets;
6246 switch(msg)
6247 {
6248 case MSG_DRAW:
6249 {
6250 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6251 for(int32_t c = 0; c < numcol; ++c)
6252 {
6253 int32_t x = (c%16)*csz, y = (c/16)*csz;
6254 rectfill(screen, d->x+x, d->y+y, d->x+x+csz-1, d->y+y+csz-1, c);
6255 if(c == d->d1)
6256 {
6257 byte highlightColor = getHighlightColor(c);
6258 rect(screen, d->x+x+0, d->y+y+0, d->x+x+csz-1, d->y+y+csz-1, highlightColor);
6259 rect(screen, d->x+x+1, d->y+y+1, d->x+x+csz-2, d->y+y+csz-2, highlightColor);
6260 }
6261 }
6262
6263 FONT *oldfont = font;
6264
6265 if(d->dp2)
6266 {
6267 font = (FONT*)d->dp2;
6268 }
6269
6270 char buf[32]={0};
6271 for(int32_t col = 0; col < 16; ++col)
6272 {
6273 sprintf(buf, "%X", col);
6274 gui_textout_ln(screen, (uint8_t*)buf, d->x + (csz*col) + (csz/2), d->y-3-text_height(font), scheme[jcBOXFG], scheme[jcBOX], 1);
6275 }
6276 for(int32_t row = 0; row < numcsets; ++row)
6277 {
6278 sprintf(buf, "%s 0x%02X", rowpref(row, alt), row*16);
6279 gui_textout_ln(screen, (uint8_t*)buf, d->x-3, d->y + (csz*row) + (csz-text_height(font))/2, scheme[jcBOXFG], scheme[jcBOX], 2);
6280 }
6281
6282 font = oldfont;
6283 break;
6284 }
6285
6286 case MSG_CLICK:
6287 {
6288 if(mouse_in_rect(d->x, d->y, d->x+d->w-1, d->y+d->h-1))
6289 {
6290 int32_t col = ((gui_mouse_x() - d->x) / csz) + 16*((gui_mouse_y() - d->y) / csz);
6291
6292 if(col>-1 && col != d->d1)
6293 {
6294 d->d1 = col;
6295 ret |= D_REDRAWME;
6296 }
6297 ret |= D_WANTFOCUS;
6298 }
6299 break;
6300 }
6301
6302 case MSG_WANTFOCUS:
6303 case MSG_LOSTFOCUS:
6304 case MSG_KEY:
6305 ret = D_WANTFOCUS;
6306 break;
6307
6308 case MSG_CHAR:
6309 {
6310 ret = D_USED_CHAR | D_REDRAWME;
6311 switch(c>>8)
6312 {
6313 case KEY_LEFT:
6314 {
6315 if(d->d1 % 0x10)
6316 --d->d1;
6317 break;
6318 }
6319 case KEY_RIGHT:
6320 {
6321 if(d->d1 % 0x10 != 0x0F)
6322 ++d->d1;
6323 break;
6324 }
6325 case KEY_UP:
6326 {
6327 if(d->d1 / 0x10)
6328 d->d1 -= 0x10;
6329 break;
6330 }
6331 case KEY_DOWN:
6332 {
6333 if(d->d1 / 0x10 != numcsets)
6334 d->d1 += 0x10;
6335 break;
6336 }
6337 case KEY_ENTER:
6338 {
6339 ret = D_CLOSE;
6340 break;
6341 }
6342 default: ret = D_O_K;
6343 }
6344 break;
6345 }
6346 }
6347 return ret;
6348 }
6349
6350 static DIALOG selcolor_dlg[] =
6351 {
6352 { jwin_win_proc, 0, 0, 306, 63+16*8, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Select Color", NULL, NULL },
6353 { jwin_button_proc, 75, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"OK", NULL, NULL },
6354 { jwin_button_proc, 164, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Cancel", NULL, NULL },
6355 { jwin_selcolor_proc, 156-64, 34, 16*8, 16*8, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6356
6357 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6358 };
6359
6360 int32_t jwin_color_swatch(int32_t msg, DIALOG *d, int32_t c)
6361 {
6362 int32_t ret = D_O_K;
6363
6364 switch(msg)
6365 {
6366 case MSG_START:
6367 {
6368 if(d->d2 < 1) d->d2 = 12;
6369 else if(d->d2 > 17) d->d2 = 17;
6370 break;
6371 }
6372
6373 case MSG_DRAW:
6374 {
6375 if(!d->d1 || (d->flags&D_DISABLED))
6376 {
6377 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1,
6378 (d->flags&D_DISABLED) ? scheme[jcDISABLED_BG] : vc(0));
6379 line(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, vc(15));
6380 line(screen, d->x, d->y+d->h-1, d->x+d->w-1, d->y, vc(15));
6381 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_DEEP);
6382 }
6383 else
6384 {
6385 int32_t c;
6386 switch(d->d1) //special cases
6387 {
6388 case BLACK:
6389 c = vc(0);
6390 break;
6391 case WHITE:
6392 c = vc(15);
6393 break;
6394 default:
6395 c = d->d1;
6396 break;
6397 }
6398 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, c);
6399 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6400 }
6401 break;
6402 }
6403
6404 case MSG_CLICK:
6405 {
6406 if(d->flags&(D_READONLY|D_DISABLED)) break;
6407 selcolor_dlg[0].dp2 = get_zc_font(font_lfont);
6408 selcolor_dlg[3].bg = scheme[jcBOXFG];
6409 selcolor_dlg[3].fg = scheme[jcBOX];
6410 selcolor_dlg[3].d1 = d->d1;
6411 selcolor_dlg[3].d2 = d->d2;
6412 large_dialog(selcolor_dlg);
6413
6414 while(gui_mouse_b()) rest(1); //wait for mouseup
6415
6416 //!TODO Move this out of jwin, and do better palette management.
6417 //!TODO Allow loading different level palettes, sprite palettes, etc via buttons
6418 PALETTE oldpal;
6419 get_palette(oldpal);
6420 bool alt = d->d2 > 16;
6421 if(!alt)
6422 {
6423 PALETTE foopal;
6424 get_palette(foopal);
6425 foopal[BLACK] = _RGB(0,0,0);
6426 foopal[WHITE] = _RGB(255,255,255);
6427 zc_set_palette(foopal);
6428 }
6429
6430 jwin_center_dialog(selcolor_dlg);
6431 int32_t val = do_zqdialog(selcolor_dlg, 3);
6432 ret = D_REDRAW;
6433
6434 zc_set_palette(oldpal);
6435 if(val == 1 || val == 3)
6436 {
6437 d->d1 = selcolor_dlg[3].d1;
6438 GUI_EVENT(d, geCHANGE_VALUE);
6439 ret |= D_REDRAWME;
6440 }
6441 if(d->flags & D_EXIT)
6442 return D_CLOSE;
6443 break;
6444 }
6445 }
6446 return ret;
6447 }
6448
6449 static DIALOG alert_dialog[] =
6450 {
6451 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6452 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6453 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6454 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6455 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6456 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6457 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6458 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6459 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6460 };
6461
6462 #define A_S1 1
6463 #define A_S2 2
6464 #define A_S3 3
6465 #define A_B1 4
6466 #define A_B2 5
6467 #define A_B3 6
6468
6469 /* jwin_alert3:
6470 * Displays a simple alert box, containing three lines of text (s1-s3),
6471 * and with either one, two, or three buttons. The text for these buttons
6472 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6473 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6474 * which button was selected.
6475 */
6476 int32_t jwin_alert3(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6477 {
6478 int32_t maxlen = 0;
6479 int32_t len1, len2, len3;
6480 int32_t avg_w = text_length(font, " ");
6481 int32_t avg_h = text_height(font)+1;
6482 int32_t buttons = 0;
6483 int32_t yofs = (title ? 22 : 0);
6484 int32_t b[3];
6485 int32_t c;
6486
6487 #define SORT_OUT_BUTTON(x) { \
6488 if (b##x) \
6489 { \
6490 alert_dialog[A_B##x].flags &= ~D_HIDDEN; \
6491 alert_dialog[A_B##x].key = c##x; \
6492 alert_dialog[A_B##x].dp = (void *)b##x; \
6493 len##x = gui_strlen(b##x); \
6494 b[buttons++] = A_B##x; \
6495 } \
6496 else \
6497 { \
6498 alert_dialog[A_B##x].flags |= D_HIDDEN; \
6499 len##x = 0; \
6500 } \
6501 }
6502
6503 if(title_font)
6504 {
6505 alert_dialog[0].dp2=title_font;
6506 }
6507
6508 alert_dialog[A_S1].dp = alert_dialog[A_S2].dp = alert_dialog[A_S3].dp =
6509 alert_dialog[A_B1].dp = alert_dialog[A_B2].dp = (void*)"";
6510
6511 if(s1)
6512 {
6513 alert_dialog[A_S1].dp = (void *)s1;
6514 maxlen = text_length(font, s1);
6515 }
6516
6517 if(s2)
6518 {
6519 alert_dialog[A_S2].dp = (void *)s2;
6520 len1 = text_length(font, s2);
6521
6522 if(len1 > maxlen)
6523 maxlen = len1;
6524 }
6525
6526 if(s3)
6527 {
6528 alert_dialog[A_S3].dp = (void *)s3;
6529 len1 = text_length(font, s3);
6530
6531 if(len1 > maxlen)
6532 maxlen = len1;
6533 }
6534
6535 SORT_OUT_BUTTON(1);
6536 SORT_OUT_BUTTON(2);
6537 SORT_OUT_BUTTON(3);
6538
6539 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6540
6541 if(len1*buttons > maxlen)
6542 maxlen = len1*buttons;
6543
6544 maxlen += avg_w*4;
6545 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6546 alert_dialog[0].w = maxlen;
6547 alert_dialog[A_S1].x = alert_dialog[A_S2].x = alert_dialog[A_S3].x =
6548 alert_dialog[0].x + maxlen/2;
6549
6550 alert_dialog[A_B1].w = alert_dialog[A_B2].w = alert_dialog[A_B3].w = len1;
6551
6552 alert_dialog[A_B1].x = alert_dialog[A_B2].x = alert_dialog[A_B3].x =
6553 alert_dialog[0].x + maxlen/2 - len1/2;
6554
6555 if(buttons == 3)
6556 {
6557 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6558 alert_dialog[b[2]].x = alert_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6559 }
6560 else if(buttons == 2)
6561 {
6562 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1 - avg_w;
6563 alert_dialog[b[1]].x = alert_dialog[0].x + maxlen/2 + avg_w;
6564 }
6565
6566 alert_dialog[0].h = avg_h*7 + 13 + yofs;
6567 alert_dialog[A_S1].y = alert_dialog[0].y + avg_h + yofs;
6568 alert_dialog[A_S2].y = alert_dialog[0].y + avg_h*2 + yofs;
6569 alert_dialog[A_S3].y = alert_dialog[0].y + avg_h*3 + yofs;
6570 alert_dialog[A_S1].h = alert_dialog[A_S2].h = alert_dialog[A_S3].h = avg_h;
6571
6572 alert_dialog[A_B1].y = alert_dialog[A_B2].y = alert_dialog[A_B3].y =
6573 alert_dialog[0].y + avg_h*5 + yofs;
6574
6575 alert_dialog[A_B1].h = alert_dialog[A_B2].h = alert_dialog[A_B3].h = avg_h+13;
6576
6577 alert_dialog[0].dp = (void *)title;
6578 alert_dialog[0].flags = (title) ? D_EXIT : 0;
6579
6580 jwin_center_dialog(alert_dialog);
6581 set_dialog_color(alert_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6582
6583 clear_keybuf();
6584
6585 do
6586 {
6587 rest(1);
6588 }
6589 while(gui_mouse_b());
6590
6591 large_dialog(alert_dialog);
6592 alert_dialog[0].d1 = 0;
6593
6594 c = do_zqdialog(alert_dialog, A_B1);
6595
6596 if(c == A_B1)
6597 return 1;
6598 else if(c == A_B2)
6599 return 2;
6600 else
6601 return 3;
6602 }
6603
6604 /* jwin_alert:
6605 * Displays a simple alert box, containing three lines of text (s1-s3),
6606 * and with either one or two buttons. The text for these buttons is passed
6607 * in b1 and b2 (b2 may be null), and the keyboard shortcuts in c1 and c2.
6608 * Returns 1 or 2 depending on which button was selected.
6609 */
6610 int32_t jwin_alert(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6611 {
6612 int32_t ret;
6613
6614 ret = jwin_alert3(title, s1, s2, s3, b1, b2, NULL, c1, c2, 0, title_font);
6615
6616 if(ret > 2)
6617 ret = 2;
6618
6619 return ret;
6620 }
6621
6622 int32_t d_autotext_proc(int32_t msg, DIALOG *d, int32_t c)
6623 {
6624 ASSERT(d);
6625 ASSERT(d->dp);
6626 #define AUTOBUF_SIZE 8092
6627 static char auto_buf[AUTOBUF_SIZE] = {0};
6628 static int32_t auto_inds[50] = {0};
6629
6630
6631 FONT *oldfont = font;
6632
6633 if (d->dp2)
6634 font = (FONT*)d->dp2;
6635 switch(msg)
6636 {
6637 case MSG_START:
6638 {
6639 memset(auto_buf, 0, AUTOBUF_SIZE);
6640 memset(auto_inds, 0, 50);
6641 char* str = (char*)d->dp;
6642 int32_t len = strlen(str);
6643 int32_t pos = 0, curstrpos = 0, linecount = 1, lastWS = -1;
6644 BITMAP* dummy = create_bitmap_ex(8,8,8);
6645 for(int32_t q = 0; q < len; ++q)
6646 {
6647 switch(str[q])
6648 {
6649 case ' ': case '\t':
6650 lastWS = pos;
6651 break;
6652 case '\n': //Forced newline
6653 auto_inds[linecount++] = ++pos;
6654 curstrpos = pos;
6655 lastWS = -1;
6656 continue; //skip rest of for loop, go to next char
6657 }
6658 auto_buf[pos++] = str[q];
6659 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //too int32_t, wrap to lower line
6660 {
6661 if(lastWS<0)
6662 {
6663 auto_buf[pos-1] = 0;
6664 auto_inds[linecount++] = pos;
6665 curstrpos = pos;
6666 auto_buf[pos++] = str[q];
6667 }
6668 else
6669 {
6670 auto_buf[lastWS] = 0;
6671 auto_inds[linecount++] = lastWS+1;
6672 curstrpos = lastWS+1;
6673 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //STILL too int32_t?
6674 {
6675 auto_buf[pos-1] = 0;
6676 auto_inds[linecount++] = pos;
6677 curstrpos = pos;
6678 auto_buf[pos++] = str[q];
6679 }
6680 lastWS = -1;
6681 }
6682 }
6683 }
6684 destroy_bitmap(dummy);
6685 d->d2 = linecount;
6686 d->h = ((text_height(font) + d->d1) * linecount) - d->d1;
6687 }
6688 break;
6689
6690 case MSG_DRAW:
6691 {
6692 int32_t fg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
6693 int32_t linecount = d->d2;
6694
6695 int32_t yinc = text_height(font)+d->d1;
6696 int32_t y = d->y;
6697 for(int32_t q = 0; q < linecount; ++q)
6698 {
6699 gui_textout_ex(screen, auto_buf+auto_inds[q], d->x, y, fg, d->bg, true);
6700 y += yinc;
6701 }
6702 }
6703 break;
6704 }
6705 font = oldfont;
6706 return D_O_K;
6707 }
6708
6709 static DIALOG alert2_dialog[] =
6710 {
6711 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6712 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6713 { d_autotext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6714 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6715 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6716 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6717 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6718 };
6719
6720 #define A2_S1 1
6721 #define A2_B1 2
6722 #define A2_B2 3
6723 #define A2_B3 4
6724
6725 /* jwin_auto_alert3:
6726 * Displays a simple alert box, containing one line of text, auto-split
6727 * across lines using 'lenlim' and 'vspace,
6728 * and with either one, two, or three buttons. The text for these buttons
6729 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6730 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6731 * which button was selected.
6732 */
6733 int32_t jwin_auto_alert3(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6734 {
6735 int32_t maxlen = 0;
6736 int32_t len1, len2, len3;
6737 int32_t avg_w = text_length(font, " ");
6738 int32_t avg_h = text_height(font)+1;
6739 int32_t buttons = 0;
6740 int32_t yofs = (title ? 22 : 0);
6741 int32_t b[3];
6742 int32_t c;
6743
6744 #define SORT_OUT_AUTOBUTTON(x) { \
6745 if (b##x) \
6746 { \
6747 alert2_dialog[A2_B##x].flags &= ~D_HIDDEN; \
6748 alert2_dialog[A2_B##x].key = c##x; \
6749 alert2_dialog[A2_B##x].dp = (void *)b##x; \
6750 len##x = gui_strlen(b##x); \
6751 b[buttons++] = A2_B##x; \
6752 } \
6753 else \
6754 { \
6755 alert2_dialog[A2_B##x].flags |= D_HIDDEN; \
6756 len##x = 0; \
6757 } \
6758 }
6759
6760 if(title_font)
6761 {
6762 alert2_dialog[0].dp2=title_font;
6763 }
6764
6765 alert2_dialog[A2_S1].dp = alert2_dialog[A2_B1].dp = alert2_dialog[A2_B2].dp = (void*)"";
6766
6767 if(s1)
6768 {
6769 alert2_dialog[A2_S1].dp = (void *)s1;
6770 maxlen = lenlim;
6771 }
6772
6773 SORT_OUT_AUTOBUTTON(1);
6774 SORT_OUT_AUTOBUTTON(2);
6775 SORT_OUT_AUTOBUTTON(3);
6776
6777 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6778
6779 if(len1*buttons > maxlen)
6780 maxlen = len1*buttons;
6781
6782 maxlen += avg_w*4;
6783 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6784
6785 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6786 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6787 alert2_dialog[A2_S1].w = lenlim;
6788 alert2_dialog[A2_S1].d1 = vspace;
6789
6790 large_dialog(alert2_dialog);
6791 alert2_dialog[0].d1 = 0;
6792
6793 object_message(&alert2_dialog[A2_S1], MSG_START, 0); //calculate height
6794
6795 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6796 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6797 alert2_dialog[A2_S1].w = lenlim;
6798 alert2_dialog[A2_S1].d1 = vspace;
6799
6800 alert2_dialog[A2_B1].w = alert2_dialog[A2_B2].w = alert2_dialog[A2_B3].w = len1;
6801
6802 alert2_dialog[A2_B1].x = alert2_dialog[A2_B2].x = alert2_dialog[A2_B3].x =
6803 alert2_dialog[0].x + maxlen/2 - len1/2;
6804
6805 if(buttons == 3)
6806 {
6807 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6808 alert2_dialog[b[2]].x = alert2_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6809 }
6810 else if(buttons == 2)
6811 {
6812 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1 - avg_w;
6813 alert2_dialog[b[1]].x = alert2_dialog[0].x + maxlen/2 + avg_w;
6814 }
6815
6816 alert2_dialog[0].w = maxlen;
6817 alert2_dialog[0].h = avg_h*4 + yofs + alert2_dialog[A2_S1].h + 13;
6818 alert2_dialog[A2_B1].y = alert2_dialog[A2_B2].y = alert2_dialog[A2_B3].y =
6819 alert2_dialog[0].y + avg_h*2 + yofs + alert2_dialog[A2_S1].h;
6820
6821 alert2_dialog[A2_B1].h = alert2_dialog[A2_B2].h = alert2_dialog[A2_B3].h = avg_h+13;
6822
6823 alert2_dialog[0].dp = (void *)title;
6824 alert2_dialog[0].flags = (title) ? D_EXIT : 0;
6825
6826 jwin_center_dialog(alert2_dialog);
6827 set_dialog_color(alert2_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6828
6829 clear_keybuf();
6830
6831 do
6832 {
6833 rest(1);
6834 }
6835 while(gui_mouse_b());
6836
6837 large_dialog(alert2_dialog);
6838 alert2_dialog[0].d1 = 0;
6839
6840 c = do_zqdialog(alert2_dialog, A2_B1);
6841
6842 if(c == A2_B1)
6843 return 1;
6844 else if(c == A2_B2)
6845 return 2;
6846 else
6847 return 3;
6848 }
6849
6850 int32_t jwin_auto_alert(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6851 {
6852 int32_t ret;
6853
6854 ret = jwin_auto_alert3(title, s1, lenlim, vspace, b1, b2, NULL, c1, c2, 0, title_font);
6855
6856 if(ret > 2)
6857 ret = 2;
6858
6859 return ret;
6860 }
6861
6862 int32_t last_droplist_sel = -1;
6863 static int32_t d_dropcancel_proc(int32_t msg,DIALOG *d,int32_t c)
6864 {
6865 //these are here to bypass compiler warnings about unused arguments
6866 d=d;
6867 c=c;
6868
6869 if(msg==MSG_CLICK || msg==MSG_DCLICK)
6870 return D_CLOSE;
6871
6872 return D_O_K;
6873 }
6874
6875 static DIALOG droplist_dlg[] =
6876 {
6877 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3)*/
6878 { d_dropcancel_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6879 { d_list_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6880 { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_ESC, (void*)close_dlg, NULL, NULL },
6881 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6882 };
6883
6884 static int32_t droplist(DIALOG *d)
6885 {
6886 ListData *data = (ListData *)d->dp;
6887 int32_t d1 = d->d1;
6888 int32_t listsize, x, y, w, h, max_w;
6889 auto oz = gui_mouse_z();
6890
6891 data->listFunc(-1, &listsize);
6892 y = d->y + d->h;
6893 h = zc_min(abc_patternmatch ? listsize+1 : listsize,8) * text_height(*data->font) + 8;
6894
6895 if(y+h >= zq_screen_h)
6896 {
6897 y = d->y - h;
6898 }
6899
6900 x = d->x;
6901 w = d->w;
6902 max_w = zc_max(d->x+d->w, zq_screen_w-d->x);
6903
6904 for(int32_t i=0; i<listsize; ++i)
6905 {
6906 w=zc_min(max_w,zc_max(w,text_length(*data->font,data->listFunc(i, NULL))+39));
6907 }
6908
6909 if(x+w >= zq_screen_w)
6910 {
6911 x=zq_screen_w-w;
6912 }
6913
6914 droplist_dlg[1] = *d;
6915 droplist_dlg[1].proc = &jwin_abclist_proc;
6916 droplist_dlg[1].flags = D_EXIT + D_USER;
6917 droplist_dlg[1].x = x;
6918 droplist_dlg[1].y = y;
6919 droplist_dlg[1].w = w;
6920 droplist_dlg[1].h = h;
6921 droplist_dlg[1].d2 = listsize<=8 ? 0 : zc_max(d1-3,0);
6922
6923 // cancel
6924 droplist_dlg[0].x = 0;
6925 droplist_dlg[0].y = 0;
6926 droplist_dlg[0].w = zq_screen_w;
6927 droplist_dlg[0].h = zq_screen_h;
6928
6929 if(do_zq_subdialog(droplist_dlg,1)==1)
6930 {
6931 position_mouse_z(oz);
6932 return droplist_dlg[1].d1;
6933 }
6934
6935 position_mouse_z(oz);
6936 return d1;
6937 }
6938
6939 /* jwin_droplist_proc:
6940 * A drop list...
6941 */
6942 int32_t jwin_droplist_proc(int32_t msg,DIALOG *d,int32_t c)
6943 {
6944 int32_t ret;
6945 int32_t down=0, last_draw=0;
6946 int32_t d1;
6947
6948 switch(msg)
6949 {
6950 case MSG_CLICK:
6951 if(mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h))
6952 goto dropit;
6953
6954 break;
6955
6956 case MSG_KEY:
6957 goto dropit;
6958 break;
6959 }
6960
6961 d1 = d->d1;
6962 ret = jwin_list_proc(msg,d,c);
6963
6964 if(d->d1!=d->d2)
6965 {
6966 d->d1=d->d2;
6967 jwin_droplist_proc(MSG_DRAW, d, 0);
6968 }
6969
6970 if(d1 != d->d1)
6971 {
6972 GUI_EVENT(d, geCHANGE_SELECTION);
6973 if(d->flags&D_EXIT)
6974 ret |= D_CLOSE;
6975 }
6976
6977 if(msg == MSG_DRAW)
6978 {
6979 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6980 }
6981
6982 return ret;
6983
6984 dropit:
6985 last_draw = 0;
6986
6987 while(gui_mouse_b())
6988 {
6989 down = mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h);
6990
6991 if(down!=last_draw)
6992 {
6993 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, down*3);
6994 last_draw = down;
6995 update_hw_screen();
6996 }
6997
6998 clear_keybuf();
6999 rest(1);
7000 }
7001
7002 if(!down)
7003 {
7004 return D_O_K;
7005 }
7006
7007 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
7008
7009 d1 = d->d1;
7010 d->d2 = d->d1 = droplist(d);
7011
7012 object_message(d, MSG_DRAW, 0);
7013
7014 while(gui_mouse_b())
7015 {
7016 clear_keybuf();
7017 rest(1);
7018 update_hw_screen();
7019 }
7020
7021 if(d1!=d->d1)
7022 GUI_EVENT(d, geCHANGE_SELECTION);
7023
7024 return ((d1 != d->d1) && (d->flags&D_EXIT)) ? D_CLOSE : D_O_K;
7025 }
7026
7027
7028 int32_t jwin_abclist_proc(int32_t msg,DIALOG *d,int32_t c)
7029 {
7030 ListData *data = (ListData *)d->dp;
7031 if(msg == MSG_START) wipe_abc_keypresses();
7032
7033 if(msg == MSG_CHAR && (key_shifts&KB_CTRL_CMD_FLAG))
7034 return D_O_K;
7035
7036 if(abc_patternmatch) // Search style pattern match.
7037 {
7038 if(msg==MSG_CHAR && ((c&0xFF) > 31) && ((c&0xFF) < 127)) //(isalpha(c&0xFF) || isdigit(c&0xFF)))
7039 {
7040 int32_t max,dummy,h;
7041
7042 h = ((d->h-3) / text_height(*data->font))-1;
7043 if ( isalpha(c&0xFF) ) c = toupper(c&0xFF);
7044 for ( int32_t q = 0; q < 1023; ++q )
7045 {
7046 if ( !(abc_keypresses[q]) )
7047 {
7048 abc_keypresses[q] = (char)c;
7049 break;
7050 }
7051 }
7052 data->listFunc(-1, &max);
7053
7054 int32_t cur = d->d1;
7055 int32_t charpos = 0; int32_t listpos = 0; int32_t lastmatch = -1;
7056 char tmp[1024] = { 0 };
7057 char lsttmp[1024] = { 0 };
7058 int32_t lastmatches[32768] = {0};
7059 for ( int32_t a = 0; a < 32768; ++a ) lastmatches[a] = -1;
7060 int32_t lmindx = 0;
7061
7062 bool foundmatch = false;
7063 bool numsearch = true;
7064 for ( int32_t q = 0; q < 1023; ++q )
7065 {
7066 if(!abc_keypresses[q]) break;
7067 if(!isdigit(abc_keypresses[q]))
7068 {
7069 if(q == 0 && abc_keypresses[q] == '-')
7070 continue;
7071 numsearch = false;
7072 break;
7073 }
7074 }
7075 if(numsearch) //Indexed search, first
7076 {
7077 int32_t num = atoi(abc_keypresses);
7078 //Find a different indexing type in the strings?
7079 if(!foundmatch)
7080 {
7081 char buf[16];
7082 if(num < 0) sprintf(buf, "(%04d)", num);
7083 else sprintf(buf, "(%03d)", num);
7084 std::string cmp = buf;
7085 for(int32_t listpos = 0; listpos < max; ++listpos)
7086 {
7087 std::string str((data->listFunc(listpos,&dummy)));
7088 size_t trimpos = str.find_last_not_of("-(0123456789)");
7089 if(trimpos != std::string::npos) ++trimpos;
7090 str.erase(0, trimpos);
7091 if(cmp == str)
7092 {
7093 d->d1 = listpos;
7094 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7095 foundmatch = true;
7096 break;
7097 }
7098 }
7099 }
7100 //Search for match with first number in string?
7101 if(!foundmatch)
7102 {
7103 auto buf = fmt::format("{}", num);
7104 for(int32_t listpos = 0; listpos < max; ++listpos)
7105 {
7106 std::string str((data->listFunc(listpos,&dummy)));
7107 size_t pos1 = -1;
7108 do
7109 {
7110 pos1 = str.find_first_of("-0123456789", pos1+1);
7111 } while(pos1 != string::npos && str[pos1] == '-' && pos1+1 < str.size() && !isdigit(str[pos1+1]));
7112 if(pos1 == string::npos)
7113 continue;
7114 size_t pos2 = str.find_first_not_of("-0123456789", pos1);
7115 if(pos2 == string::npos)
7116 continue;
7117 str = str.substr(pos1,pos2-pos1);
7118 if(buf == str)
7119 {
7120 d->d1 = listpos;
7121 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7122 foundmatch = true;
7123 break;
7124 }
7125 }
7126 }
7127 }
7128 if(!foundmatch)
7129 {
7130 strcpy(tmp, abc_keypresses);
7131 for ( int32_t listpos = 0; listpos < max; ++listpos )
7132 {
7133 memset(lsttmp, 0, 1024);
7134 strcpy(lsttmp, ((data->listFunc(listpos,&dummy))));
7135
7136 if ( !(strnicmp(lsttmp, tmp, strlen(tmp))))
7137 {
7138 d->d1 = listpos;
7139 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7140 foundmatch = true;
7141 break;
7142 }
7143 }
7144 }
7145 if(foundmatch)
7146 GUI_EVENT(d, geCHANGE_SELECTION);
7147 d->flags |= D_DIRTY;
7148 if ( gui_mouse_b() ) wipe_abc_keypresses();
7149 return foundmatch ? D_USED_CHAR : D_O_K;
7150 }
7151 else if(msg==MSG_CHAR && ( (c&0xFF) == 8) )//backspace
7152 {
7153 for ( int32_t q = 1023; q >= 0; --q )
7154 {
7155 if ( abc_keypresses[q] )
7156 {
7157 d->flags |= D_DIRTY;
7158 abc_keypresses[q] = '\0'; break;
7159 }
7160 }
7161 return D_USED_CHAR;
7162 }
7163 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7164 }
7165 else // Windows Explorer style jumping
7166 {
7167 if(msg==MSG_CHAR && (isalpha(c&0xFF) || isdigit(c&0xFF)))
7168 {
7169 int32_t max,dummy,h,i;
7170
7171 h = (d->h-3) / text_height(*data->font);
7172 c = toupper(c&0xFF);
7173
7174 data->listFunc(-1, &max);
7175
7176 int32_t cur = d->d1;
7177 bool foundmatch = false;
7178 for(i=cur+1; (cur ? (i != cur) : (cur < max)); ++i) //don't infinite loop this.
7179 {
7180 if(i>=max) i=0;
7181 if(toupper((data->listFunc(i,&dummy))[0]) == c)
7182 {
7183 d->d1 = i;
7184 d->d2 = zc_max(zc_min(i-(h>>1), max-h), 0);
7185 foundmatch = true;
7186 break;
7187 }
7188 }
7189
7190 d->flags |= D_DIRTY;
7191 return foundmatch ? D_USED_CHAR : D_O_K;
7192 }
7193 }
7194 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7195 return ((abc_patternmatch) ? jwin_do_abclist_proc(msg,d,c) : jwin_list_proc(msg,d,c));
7196 }
7197
7198 int32_t jwin_checkfont_proc(int32_t msg, DIALOG *d, int32_t c)
7199 {
7200
7201 FONT *oldfont = font;
7202
7203 if(d->dp2)
7204 {
7205 font = (FONT *)d->dp2;
7206 }
7207
7208 int32_t rval = jwin_check_proc(msg, d, c);
7209 font = oldfont;
7210 return rval;
7211 }
7212
7213 /* jwin_check_proc:
7214 * Who needs C++ after all? This is derived from d_button_proc,
7215 * but overrides the drawing routine to provide a check box.
7216 */
7217 int32_t jwin_check_proc(int32_t msg, DIALOG *d, int32_t c)
7218 {
7219 //these are here to bypass compiler warnings about unused arguments
7220 c=c;
7221 int32_t x;
7222 int32_t bx=0, tl=0;
7223 int32_t tx=d->x;
7224 ASSERT(d);
7225
7226 switch(msg)
7227 {
7228 case MSG_DRAW:
7229 x = d->x;
7230
7231 if(!(d->d1))
7232 {
7233 if(d->dp)
7234 {
7235 if(d->flags & D_DISABLED)
7236 {
7237 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7238 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7239 bx=tl+text_height(font)/2;
7240 }
7241 else
7242 {
7243 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7244 bx=tl+text_height(font)/2;
7245 }
7246 }
7247 }
7248
7249 jwin_draw_frame(screen, x+bx, d->y, d->h, d->h, FR_DEEP);
7250
7251 if(!(d->flags & D_DISABLED))
7252 {
7253 rectfill(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTBG]);
7254 }
7255
7256 if(d->d1)
7257 {
7258 tx=x+bx+d->h-1+(text_height(font)/2);
7259
7260 if(d->dp)
7261 {
7262 if(d->flags & D_DISABLED)
7263 {
7264 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7265 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7266 }
7267 else
7268 {
7269 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7270 }
7271 }
7272 }
7273
7274 if(d->flags & D_SELECTED)
7275 {
7276 line(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTFG]);
7277 line(screen, x+bx+2, d->y+d->h-3, x+bx+d->h-3, d->y+2, scheme[jcTEXTFG]);
7278 }
7279
7280 d->w=int32_t(text_height(font)*1.5);
7281
7282 if(d->dp)
7283 {
7284 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7285 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7286 d->w+=tl+1;
7287 }
7288
7289 return D_O_K;
7290 break;
7291 }
7292
7293 return d_jwinbutton_proc(msg, d, 0);
7294 }
7295
7296 int32_t jwin_radiofont_proc(int32_t msg, DIALOG *d, int32_t c)
7297 {
7298 FONT *oldfont = font;
7299
7300 if(d->dp2)
7301 {
7302 font = (FONT *)d->dp2;
7303 }
7304
7305 int32_t rval = jwin_radio_proc(msg, d, c);
7306 font = oldfont;
7307 return rval;
7308 }
7309
7310 /* jwin_radio_proc:
7311 * GUI procedure for radio buttons.
7312 * Parameters: d1-button group number; d2-button style (0=circle,1=square);
7313 * dp-text to appear as label to the right of the button.
7314 */
7315 int32_t jwin_radio_proc(int32_t msg, DIALOG *d, int32_t c)
7316 {
7317 int32_t x, center, r, ret, tl=0, tx;
7318 ASSERT(d);
7319
7320 switch(msg)
7321 {
7322 case MSG_DRAW:
7323 // tx=d->x+d->h-1+text_height(font);
7324 tx=d->x+int32_t(text_height(font)*1.5);
7325
7326 if(d->dp)
7327 {
7328 if(d->flags & D_DISABLED)
7329 {
7330 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7331 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7332 }
7333 else
7334 {
7335 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7336 }
7337 }
7338
7339 x = d->x;
7340 r = d->h/2;
7341
7342 center = x+r;
7343 rectfill(screen, x, d->y, x+d->h-1, d->y+d->h-1, scheme[jcBOX]);
7344
7345 switch(d->d2)
7346 {
7347 case 1:
7348 jwin_draw_frame(screen, x, d->y, d->h, d->h, FR_DEEP);
7349
7350 if(!(d->flags & D_DISABLED))
7351 {
7352 rectfill(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcLIGHT]);
7353 }
7354
7355 if(d->flags & D_SELECTED)
7356 {
7357 rectfill(screen, x+r/2, d->y+r/2, x+d->h-1-r/2, d->y+d->h-1-r/2, scheme[jcDARK]);
7358 //line(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcDARK]);
7359 //line(screen, x+2, d->y+d->h-3, x+d->h-3, d->y+2, scheme[jcDARK]);
7360 }
7361
7362 break;
7363
7364 default:
7365 circlefill(screen, center, d->y+r, r, scheme[jcTEXTBG]);
7366 arc(screen, center, d->y+r, itofix(32), itofix(160), r, vc(0));
7367 circlefill(screen, center, d->y+r, r-1, scheme[jcTEXTBG]);
7368 arc(screen, center, d->y+r, itofix(32), itofix(160), r-1, vc(0));
7369 circlefill(screen, center, d->y+r, r-2, (d->flags & D_DISABLED)?scheme[jcDISABLED_BG]:scheme[jcTEXTBG]);
7370
7371 if(d->flags & D_SELECTED)
7372 {
7373 circlefill(screen, center, d->y+r, r-3, scheme[jcTEXTFG]);
7374 }
7375
7376 break;
7377 }
7378
7379 if(d->dp)
7380 {
7381 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7382 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7383 d->w=tl+int32_t(text_height(font)*1.5)+1;
7384 }
7385
7386 return D_O_K;
7387
7388 case MSG_KEY:
7389 case MSG_CLICK:
7390 if(d->flags & D_SELECTED)
7391 {
7392 return D_O_K;
7393 }
7394
7395 break;
7396
7397 case MSG_RADIO:
7398 if((c == d->d1) && (d->flags & D_SELECTED))
7399 {
7400 d->flags &= ~D_SELECTED;
7401 object_message(d, MSG_DRAW, 0);
7402 }
7403
7404 break;
7405 }
7406
7407 ret = d_jwinbutton_proc(msg, d, 0);
7408
7409 if(((msg==MSG_KEY) || (msg==MSG_CLICK)) && (d->flags & D_SELECTED) && (!(d->flags & D_EXIT)))
7410 {
7411 d->flags &= ~D_SELECTED;
7412 broadcast_dialog_message(MSG_RADIO, d->d1);
7413 d->flags |= D_SELECTED;
7414 GUI_EVENT(d, geRADIO);
7415 }
7416
7417 return ret;
7418 }
7419
7420
7421 /* 1.5k lookup table for color matching */
7422 uint32_t col_diff[3*128];
7423
7424 /* bestfit_init:
7425 * Color matching is done with weighted squares, which are much faster
7426 * if we pregenerate a little lookup table...
7427 */
7428 void bestfit_init(void)
7429 {
7430 int32_t i;
7431
7432 col_diff[0] = col_diff[128] = col_diff[256] = 0;
7433
7434 for(i=1; i<64; i++)
7435 {
7436 int32_t k = i * i;
7437 col_diff[0 +i] = col_diff[0 +128-i] = k * (59 * 59);
7438 col_diff[128+i] = col_diff[128+128-i] = k * (30 * 30);
7439 col_diff[256+i] = col_diff[256+128-i] = k * (11 * 11);
7440 }
7441 }
7442
7443
7444
7445 /* bestfit_color:
7446 * Searches a palette for the color closest to the requested R, G, B value.
7447 */
7448 int32_t bestfit_color_range(AL_CONST PALETTE pal, int32_t r, int32_t g, int32_t b, uint8_t start, uint8_t end)
7449 {
7450 int32_t i, coldiff, lowest, bestfit;
7451
7452 if(col_diff[1] == 0)
7453 bestfit_init();
7454
7455 bestfit = start;
7456 lowest = INT_MAX;
7457
7458 i = start;
7459
7460 while(i<PAL_SIZE&&i<=end)
7461 {
7462 AL_CONST RGB *rgb = &pal[i];
7463 coldiff = (col_diff + 0) [(rgb->g - g) & 0x7F ];
7464
7465 if(coldiff < lowest)
7466 {
7467 coldiff += (col_diff + 128) [(rgb->r - r) & 0x7F ];
7468
7469 if(coldiff < lowest)
7470 {
7471 coldiff += (col_diff + 256) [(rgb->b - b) & 0x7F ];
7472
7473 if(coldiff < lowest)
7474 {
7475 bestfit = rgb - pal; /* faster than `bestfit = i;' */
7476
7477 if(coldiff == 0)
7478 {
7479 return bestfit;
7480 }
7481
7482 lowest = coldiff;
7483 }
7484 }
7485 }
7486
7487 i++;
7488 }
7489
7490 return bestfit;
7491 }
7492
7493
7494 /* makecol8:
7495 * Converts R, G, and B values (ranging 0-255) to an 8 bit paletted color.
7496 * If the global rgb_map table is initialised, it uses that, otherwise
7497 * it searches through the current palette to find the best match.
7498 */
7499 int32_t makecol8_map(int32_t r, int32_t g, int32_t b, RGB_MAP *table)
7500 {
7501 return table->data[r>>3][g>>3][b>>3];
7502 }
7503
7504
7505 /* create_rgb_table:
7506 * Fills an RGB_MAP lookup table with conversion data for the specified
7507 * palette. This is the faster version by Jan Hubicka.
7508 *
7509 * Uses alg. similar to floodfill - it adds one seed per every color in
7510 * palette to its best position. Then areas around seed are filled by
7511 * same color because it is best approximation for them, and then areas
7512 * about them etc...
7513 *
7514 * It does just about 80000 tests for distances and this is about 100
7515 * times better than normal 256*32000 tests so the calculation time
7516 * is now less than one second at all computers I tested.
7517 */
7518 void create_rgb_table_range(RGB_MAP *table, AL_CONST PALETTE pal_8bit, uint8_t start, uint8_t end, void (*callback)(int32_t pos))
7519 {
7520 #define UNUSED 65535
7521 #define LAST 65532
7522
7523 // Allegro has been modified to use an 8 bit palette, but this method and RGB_MAP still use 6 bit.
7524 PALETTE pal;
7525 for (int i = 0; i < 256; i++)
7526 {
7527 pal[i] = pal_8bit[i];
7528 pal[i].r /= 4;
7529 pal[i].g /= 4;
7530 pal[i].b /= 4;
7531 }
7532
7533 /* macro add adds to single linked list */
7534 #define add(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7535 (first != LAST ? (next[last] = (i)) : (first = (i))), \
7536 (last = (i))) : 0)
7537
7538 /* same but w/o checking for first element */
7539 #define add1(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7540 next[last] = (i), \
7541 (last = (i))) : 0)
7542
7543 /* calculates distance between two colors */
7544 #define dist(a1, a2, a3, b1, b2, b3) \
7545 (col_diff[ ((a2) - (b2)) & 0x7F] + \
7546 (col_diff + 128)[((a1) - (b1)) & 0x7F] + \
7547 (col_diff + 256)[((a3) - (b3)) & 0x7F])
7548
7549 /* converts r,g,b to position in array and back */
7550 #define pos(r, g, b) \
7551 (((r) / 2) * 32 * 32 + ((g) / 2) * 32 + ((b) / 2))
7552
7553 #define depos(pal, r, g, b) \
7554 ((b) = ((pal) & 31) * 2, \
7555 (g) = (((pal) >> 5) & 31) * 2, \
7556 (r) = (((pal) >> 10) & 31) * 2)
7557
7558 /* is current color better than pal1? */
7559 #define better(r1, g1, b1, pal1) \
7560 (((int32_t)dist((r1), (g1), (b1), \
7561 (pal1).r, (pal1).g, (pal1).b)) > (int32_t)dist2)
7562
7563 /* checking of position */
7564 #define dopos(rp, gp, bp, ts) \
7565 if ((rp > -1 || r > 0) && (rp < 1 || r < 61) && \
7566 (gp > -1 || g > 0) && (gp < 1 || g < 61) && \
7567 (bp > -1 || b > 0) && (bp < 1 || b < 61)) { \
7568 i = first + rp * 32 * 32 + gp * 32 + bp; \
7569 if (!data[i]) { \
7570 data[i] = val; \
7571 add1(i); \
7572 } \
7573 else if ((ts) && (data[i] != val)) { \
7574 dist2 = (rp ? (col_diff+128)[(r+2*rp-pal[val].r) & 0x7F] : r2) + \
7575 (gp ? (col_diff )[(g+2*gp-pal[val].g) & 0x7F] : g2) + \
7576 (bp ? (col_diff+256)[(b+2*bp-pal[val].b) & 0x7F] : b2); \
7577 if (better((r+2*rp), (g+2*gp), (b+2*bp), pal[data[i]])) { \
7578 data[i] = val; \
7579 add1(i); \
7580 } \
7581 } \
7582 }
7583
7584 int32_t i, curr, r, g, b, val, dist2;
7585 uint32_t r2, g2, b2;
7586 uint16_t next[32*32*32];
7587 uint8_t *data;
7588 int32_t first = LAST;
7589 int32_t last = LAST;
7590 int32_t count = 0;
7591 int32_t cbcount = 0;
7592
7593 #define AVERAGE_COUNT 18000
7594
7595 if(col_diff[1] == 0)
7596 bestfit_init();
7597
7598 memset(next, 255, sizeof(next));
7599 memset(table->data, 0, sizeof(char)*32*32*32);
7600
7601 data = (uint8_t *)table->data;
7602
7603 /* add starting seeds for floodfill */
7604 for(i=start; i<PAL_SIZE&&i<=end; i++)
7605 {
7606 curr = pos(pal[i].r, pal[i].g, pal[i].b);
7607
7608 if(next[curr] == UNUSED)
7609 {
7610 data[curr] = i;
7611 add(curr);
7612 }
7613 }
7614
7615 /* main floodfill: two versions of loop for faster growing in blue axis */
7616 while(first < LAST)
7617 {
7618 depos(first, r, g, b);
7619
7620 /* calculate distance of current color */
7621 val = data[first];
7622 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7623 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7624 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7625
7626 /* try to grow to all directions */
7627 #ifdef _MSC_VER
7628 #pragma warning(disable:4127)
7629 #endif
7630 dopos(0, 0, 1, 1);
7631 dopos(0, 0,-1, 1);
7632 dopos(1, 0, 0, 1);
7633 dopos(-1, 0, 0, 1);
7634 dopos(0, 1, 0, 1);
7635 dopos(0,-1, 0, 1);
7636 #ifdef _MSC_VER
7637 #pragma warning(default:4127)
7638 #endif
7639
7640 /* faster growing of blue direction */
7641 if((b > 0) && (data[first-1] == val))
7642 {
7643 b -= 2;
7644 first--;
7645 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7646
7647 #ifdef _MSC_VER
7648 #pragma warning(disable:4127)
7649 #endif
7650 dopos(-1, 0, 0, 0);
7651 dopos(1, 0, 0, 0);
7652 dopos(0,-1, 0, 0);
7653 dopos(0, 1, 0, 0);
7654 #ifdef _MSC_VER
7655 #pragma warning(default:4127)
7656 #endif
7657
7658 first++;
7659 }
7660
7661 /* get next from list */
7662 i = first;
7663 first = next[first];
7664 next[i] = UNUSED;
7665
7666 /* second version of loop */
7667 if(first != LAST)
7668 {
7669 depos(first, r, g, b);
7670
7671 val = data[first];
7672 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7673 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7674 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7675
7676 #ifdef _MSC_VER
7677 #pragma warning(disable:4127)
7678 #endif
7679 dopos(0, 0, 1, 1);
7680 dopos(0, 0,-1, 1);
7681 dopos(1, 0, 0, 1);
7682 dopos(-1, 0, 0, 1);
7683 dopos(0, 1, 0, 1);
7684 dopos(0,-1, 0, 1);
7685 #ifdef _MSC_VER
7686 #pragma warning(default:4127)
7687 #endif
7688
7689 if((b < 61) && (data[first + 1] == val))
7690 {
7691 b += 2;
7692 first++;
7693 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7f];
7694
7695 #ifdef _MSC_VER
7696 #pragma warning(disable:4127)
7697 #endif
7698 dopos(-1, 0, 0, 0);
7699 dopos(1, 0, 0, 0);
7700 dopos(0,-1, 0, 0);
7701 dopos(0, 1, 0, 0);
7702 #ifdef _MSC_VER
7703 #pragma warning(default:4127)
7704 #endif
7705
7706 first--;
7707 }
7708
7709 i = first;
7710 first = next[first];
7711 next[i] = UNUSED;
7712 }
7713
7714 count++;
7715
7716 if(count == (cbcount+1)*AVERAGE_COUNT/256)
7717 {
7718 if(cbcount < 256)
7719 {
7720 if(callback)
7721 callback(cbcount);
7722
7723 cbcount++;
7724 }
7725 }
7726 }
7727
7728 if(callback)
7729 while(cbcount < 256)
7730 callback(cbcount++);
7731 }
7732
7733 int32_t short_bmp_avg(BITMAP *bmp, int32_t i)
7734 {
7735 int32_t j=((int16_t *)bmp->line[0])[i];
7736 int32_t r=getr15(j);
7737 int32_t g=getg15(j);
7738 int32_t b=getb15(j);
7739 int32_t k=1;
7740
7741 if(i>0)
7742 {
7743 j=((int16_t *)bmp->line[0])[i-1];
7744 r+=getr15(j);
7745 g+=getg15(j);
7746 b+=getb15(j);
7747 ++k;
7748 }
7749
7750 if(i<(bmp->w-2))
7751 {
7752 j=((int16_t *)bmp->line[0])[i+1];
7753 r+=getr15(j);
7754 g+=getg15(j);
7755 b+=getb15(j);
7756 ++k;
7757 }
7758
7759 r/=k;
7760 g/=k;
7761 b/=k;
7762 return makecol15(r, g, b);
7763 }
7764
7765 // A consistent RENG (random enough number generator) for dither_rect()
7766 static uint16_t lfsr;
7767
7768 void lfsrInit()
7769 {
7770 lfsr=1;
7771 }
7772
7773 uint16_t lfsrNext()
7774 {
7775 auto bits=(lfsr^(lfsr>>2)^(lfsr>>3)^(lfsr>>5))&1;
7776 lfsr=(lfsr>>1)|(bits<<15);
7777 return lfsr;
7778 }
7779
7780 void dither_rect(BITMAP *bmp, PALETTE *pal, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
7781 int32_t src_color1, int32_t src_color2, uint8_t dest_color1,
7782 uint8_t dest_color2)
7783 {
7784 BITMAP *src_bmp=create_bitmap_ex(15, abs(x2-x1)+1, 1);
7785 BITMAP *dest_bmp=create_bitmap_ex(8, abs(x2-x1)+1, abs(y2-y1)+1);
7786 int32_t r, g, b, direction=1;
7787 int32_t c;
7788 int32_t r1, r2, g1, g2, b1, b2;
7789 int32_t (*diff[2])[3];
7790 diff[0] = new int32_t[x2-x1+3][3];
7791 diff[1] = new int32_t[x2-x1+3][3];
7792 int32_t cdiff[3];
7793 RGB_MAP table;
7794 int32_t temp;
7795 int32_t red_rand_strength=0, green_rand_strength=0, blue_rand_strength=0;
7796
7797 lfsrInit();
7798 clear_bitmap(dest_bmp);
7799
7800 if(x1>x2)
7801 {
7802 temp=x1;
7803 x1=x2;
7804 x2=temp;
7805 }
7806
7807 if(y1>y2)
7808 {
7809 temp=y1;
7810 y1=y2;
7811 y2=temp;
7812 }
7813
7814 if(src_color1>src_color2)
7815 {
7816 temp=src_color1;
7817 src_color1=src_color2;
7818 src_color2=temp;
7819 }
7820
7821 if(dest_color1>dest_color2)
7822 {
7823 temp=dest_color1;
7824 dest_color1=dest_color2;
7825 dest_color2=temp;
7826 }
7827
7828 create_rgb_table_range(&table, *pal, dest_color1, dest_color2, NULL);
7829 r1=getr15(src_color1);
7830 r2=getr15(src_color2);
7831 g1=getg15(src_color1);
7832 g2=getg15(src_color2);
7833 b1=getb15(src_color1);
7834 b2=getb15(src_color2);
7835 red_rand_strength=getr8(dest_color1+1)-getr8(dest_color1);
7836 green_rand_strength=getg8(dest_color1+1)-getg8(dest_color1);
7837 blue_rand_strength=getb8(dest_color1+1)-getb8(dest_color1);
7838 memset(cdiff,0,3*sizeof(float));
7839 memset(diff[0],0,(x2-x1+3)*3*sizeof(int32_t));
7840 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7841 int32_t mc, mr, mg, mb;
7842
7843 for(int32_t i=0; i<src_bmp->w; i++)
7844 {
7845 r = mix_value(r1, r2, i, src_bmp->w-1);
7846 g = mix_value(g1, g2, i, src_bmp->w-1);
7847 b = mix_value(b1, b2, i, src_bmp->w-1);
7848 c = makecol15(r,g,b);
7849 ((int16_t *)src_bmp->line[0])[i] = c;
7850 }
7851
7852 uint8_t tempcolor, origcolor;
7853
7854 for(int32_t j=0; j<=y2-y1; ++j)
7855 {
7856 if(direction==1)
7857 {
7858 for(int32_t i=0; i<=x2-x1; ++i)
7859 {
7860 mc=((int16_t *)src_bmp->line[0])[i];
7861 mr=bound(getr15(mc)+lfsrNext()%(red_rand_strength*2+1)-(red_rand_strength*1),0,255);
7862 mg=bound(getg15(mc)+lfsrNext()%(green_rand_strength*2+1)-(green_rand_strength*1),0,255);
7863 mb=bound(getb15(mc)+lfsrNext()%(blue_rand_strength*2+1)-(blue_rand_strength*1),0,255);
7864 cdiff[0]=bound(mr+
7865 diff[0][i][0]+
7866 diff[0][i+1][0]+
7867 diff[0][i+2][0]+
7868 cdiff[0],0,255);
7869 cdiff[1]=bound(mg+
7870 diff[0][i][1]+
7871 diff[0][i+1][1]+
7872 diff[0][i+2][1]+
7873 cdiff[1],0,255);
7874 cdiff[2]=bound(mb+
7875 diff[0][i][2]+
7876 diff[0][i+1][2]+
7877 diff[0][i+2][2]+
7878 cdiff[2],0,255);
7879 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7880 origcolor=makecol8_map(mr,mg,mb,&table);
7881 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7882 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7883 dest_bmp->line[j][i]=tempcolor;
7884 r=getr8(tempcolor);
7885 g=getg8(tempcolor);
7886 b=getb8(tempcolor);
7887 diff[1][i][0]=(cdiff[0]-r)*3/16;
7888 diff[1][i][1]=(cdiff[1]-g)*3/16;
7889 diff[1][i][2]=(cdiff[2]-b)*3/16;
7890 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7891 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7892 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7893 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7894 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7895 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7896 cdiff[0]=(cdiff[0]-r)*7/16;
7897 cdiff[1]=(cdiff[1]-g)*7/16;
7898 cdiff[2]=(cdiff[2]-b)*7/16;
7899 }
7900
7901 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(int32_t));
7902 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7903 direction=-1;
7904 }
7905 else
7906 {
7907 for(int32_t i=x2-x1; i>=0; --i)
7908 {
7909 mc=((int16_t *)src_bmp->line[0])[i];
7910 mr=getr15(mc);
7911 mg=getg15(mc);
7912 mb=getb15(mc);
7913 cdiff[0]=bound(mr+
7914 diff[0][i][0]+
7915 diff[0][i+1][0]+
7916 diff[0][i+2][0]+
7917 cdiff[0],0,255);
7918 cdiff[1]=bound(mg+
7919 diff[0][i][1]+
7920 diff[0][i+1][1]+
7921 diff[0][i+2][1]+
7922 cdiff[1],0,255);
7923 cdiff[2]=bound(mb+
7924 diff[0][i][2]+
7925 diff[0][i+1][2]+
7926 diff[0][i+2][2]+
7927 cdiff[2],0,255);
7928 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7929 origcolor=makecol8_map(mr,mg,mb,&table);
7930 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7931 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7932 dest_bmp->line[j][i]=tempcolor;
7933 r=getr8(tempcolor);
7934 g=getg8(tempcolor);
7935 b=getb8(tempcolor);
7936 diff[1][i][0]=(cdiff[0]-r)*3/16;
7937 diff[1][i][1]=(cdiff[1]-g)*3/16;
7938 diff[1][i][2]=(cdiff[2]-b)*3/16;
7939 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7940 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7941 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7942 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7943 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7944 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7945 cdiff[0]=(cdiff[0]-r)*7/16;
7946 cdiff[1]=(cdiff[1]-g)*7/16;
7947 cdiff[2]=(cdiff[2]-b)*7/16;
7948 }
7949
7950 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(float));
7951 memset(diff[1],0,(x2-x1+3)*3*sizeof(float));
7952 direction=1;
7953 }
7954 }
7955
7956 blit(dest_bmp, bmp, 0, 0, x1, y1, x2-x1+1, y2-y1+1);
7957 delete[] diff[1];
7958 delete[] diff[0];
7959 destroy_bitmap(src_bmp);
7960 destroy_bitmap(dest_bmp);
7961 return;
7962 }
7963
7964 bool do_text_button(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7965 {
7966 bool over=false;
7967
7968 while(gui_mouse_b())
7969 {
7970 if(mouse_in_rect(x,y,w,h))
7971 {
7972 if(!over)
7973 {
7974 vsync();
7975 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7976 over=true;
7977 update_hw_screen();
7978 }
7979 }
7980 else
7981 {
7982 if(over)
7983 {
7984 vsync();
7985 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7986 over=false;
7987 update_hw_screen();
7988 }
7989 }
7990 rest(1);
7991 }
7992
7993 return over;
7994 }
7995
7996 bool do_text_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7997 {
7998 bool over=false;
7999
8000 while(gui_mouse_b())
8001 {
8002 //vsync();
8003 if(mouse_in_rect(x,y,w,h))
8004 {
8005 if(!over)
8006 {
8007 vsync();
8008 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
8009 over=true;
8010
8011 update_hw_screen();
8012 }
8013 }
8014 else
8015 {
8016 if(over)
8017 {
8018 vsync();
8019 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
8020 over=false;
8021
8022 update_hw_screen();
8023 }
8024 }
8025 rest(1);
8026 }
8027
8028 if(over)
8029 {
8030 vsync();
8031 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
8032
8033 update_hw_screen();
8034 }
8035
8036 return over;
8037 }
8038 bool do_icon_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,int icon)
8039 {
8040 bool over=false;
8041
8042 while(gui_mouse_b())
8043 {
8044 //vsync();
8045 if(mouse_in_rect(x,y,w,h))
8046 {
8047 if(!over)
8048 {
8049 vsync();
8050 jwin_draw_icon_button(screen, x, y, w, h, icon, D_SELECTED, true);
8051 over=true;
8052
8053 update_hw_screen();
8054 }
8055 }
8056 else
8057 {
8058 if(over)
8059 {
8060 vsync();
8061 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8062 over=false;
8063
8064 update_hw_screen();
8065 }
8066 }
8067 rest(1);
8068 }
8069
8070 if(over)
8071 {
8072 vsync();
8073 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8074
8075 update_hw_screen();
8076 }
8077
8078 return over;
8079 }
8080
8081 int32_t jwin_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8082 {
8083 int32_t i;
8084 int32_t tx;
8085 int32_t sd=2; //selected delta
8086 TABPANEL *panel=(TABPANEL *)d->dp;
8087 DIALOG *panel_dialog=NULL, *current_object=NULL;
8088 int32_t selected=0;
8089 int32_t counter=0;
8090 ASSERT(d);
8091 int32_t temp_d, temp_d2;
8092
8093 if(d->dp==NULL) return D_O_K;
8094
8095 panel_dialog=(DIALOG *)d->dp3;
8096
8097 if (msg != MSG_START && msg != MSG_END)
8098 {
8099 bool redraw = false;
8100 for (i = 0; panel[i].text; ++i)
8101 {
8102 if ((panel[i].flags & D_SELECTED) && !(d->flags & D_HIDDEN))
8103 {
8104 for (counter = 0; counter < panel[i].objects; counter++)
8105 {
8106 current_object = panel_dialog + (panel[i].dialog[counter]);
8107 current_object->flags &= ~D_HIDDEN;
8108 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8109 redraw = true;
8110 }
8111 }
8112 else
8113 {
8114 for (counter = 0; counter < panel[i].objects; counter++)
8115 {
8116 current_object = panel_dialog + (panel[i].dialog[counter]);
8117 current_object->flags |= D_HIDDEN;
8118 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8119 redraw = true;
8120 }
8121 }
8122
8123 /*if (d->flags & D_HIDDEN)
8124 {
8125 for(counter=0; counter<panel[i].objects; counter++)
8126 {
8127 current_object=panel_dialog+(panel[i].dialog[counter]);
8128 current_object->x=zq_screen_w*3;
8129 current_object->y=zq_screen_h*3;
8130 }
8131 }*/
8132 }
8133 if (redraw)
8134 broadcast_dialog_message(MSG_DRAW, 0);
8135 }
8136 FONT *oldfont = font;
8137 switch(msg)
8138 {
8139 case MSG_DRAW:
8140 {
8141 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8142 {
8143 if(d->dp2)
8144 {
8145 font = (FONT *)d->dp2;
8146 }
8147
8148 panel_dialog=(DIALOG *)d->dp3;
8149 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8150 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8151 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8152 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8153 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8154 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8155 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8156 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8157 tx=d->x;
8158
8159 if(d->dp)
8160 {
8161 if(!(panel[((d->d1&0xFF00)>>8)].flags&D_SELECTED))
8162 {
8163 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8164 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8165 }
8166
8167 tx+=2;
8168
8169 for(i=0; panel[i].text; ++i)
8170 {
8171 if(panel[i].flags&D_SELECTED)
8172 {
8173 selected=i;
8174 }
8175 }
8176
8177 for(i=((d->d1&0xFF00)>>8); panel[i].text&&i<=last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w); ++i)
8178 {
8179 sd=(panel[i].flags&D_SELECTED)?0:2;
8180
8181 if((i==((d->d1&0xFF00)>>8)) || (!(panel[i-1].flags&D_SELECTED)))
8182 {
8183 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8184 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8185 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8186 }
8187
8188 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcLIGHT]); //top
8189 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcMEDLT]); //top
8190
8191 if(!(panel[i].flags&D_SELECTED))
8192 {
8193 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcLIGHT]); //bottom
8194 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcMEDLT]); //bottom
8195 }
8196
8197 tx+=4;
8198 gui_textout_ln(screen, (uint8_t*)panel[i].text, tx+4, d->y+sd+4, scheme[jcBOXFG], scheme[jcBOX], 0);
8199 tx+=text_length(font, (char *)panel[i].text)+10;
8200
8201 if(!(panel[i+1].text) || (!(panel[i+1].flags&D_SELECTED)))
8202 {
8203 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8204 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8205 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8206 }
8207
8208 tx++;
8209 }
8210
8211 if(((d->d1&0xFF00)>>8)!=0||last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w)+1<tab_count(panel))
8212 {
8213 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8214 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8215 }
8216 }
8217
8218 if((tx+(2-sd))<(d->x+d->w))
8219 {
8220 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8221 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8222 }
8223
8224 font = oldfont;
8225
8226 //what dialog is this tab control in (programmer must set manually)
8227 panel_dialog=(DIALOG *)d->dp3;
8228
8229 //for each object handled by the currently selected tab...
8230 for(counter=0; counter<panel[selected].objects; counter++)
8231 {
8232 //assign current_object to one of the controls handled by the tab
8233 current_object=panel_dialog+(panel[selected].dialog[counter]);
8234 //remember the x and y positions of the control
8235 current_object->x=panel[selected].xy[counter*2];
8236 current_object->y=panel[selected].xy[counter*2+1];
8237 object_message(current_object, MSG_DRAW, 0);
8238 }
8239
8240 //if there was a previously selected tab...
8241 if((d->d1&0x00FF)!=0x00FF)
8242 {
8243 //for each object handled by the tab
8244 for(counter=0; counter<panel[d->d1&0xFF].objects; counter++)
8245 {
8246 //assign current_object to one of the controls handled by the tab
8247 current_object=panel_dialog+(panel[d->d1&0xFF].dialog[counter]);
8248 // //remember the x and y positions of the control
8249 // panel[d->d1].xy[counter*2]=current_object->x;
8250 // panel[d->d1].xy[counter*2+1]=current_object->y;
8251 current_object->x=zq_screen_w*3;
8252 current_object->y=zq_screen_h*3;
8253 }
8254 }
8255 }
8256 }
8257 break;
8258
8259 case MSG_CLICK:
8260 {
8261 d->d1&=0xFF00;
8262 d->d1|=0x00FF;
8263 if(d->dp2)
8264 {
8265 font = (FONT *)d->dp2;
8266 }
8267
8268 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8269 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8270 {
8271 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8272 {
8273 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8274 {
8275 temp_d=((d->d1&0xFF00)>>8);
8276 temp_d2=(d->d1&0x00FF);
8277
8278 if(temp_d>0)
8279 {
8280 --temp_d;
8281 }
8282
8283 d->d1=(temp_d<<8)|temp_d2;
8284 d->flags|=D_DIRTY;
8285 }
8286 }
8287 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8288 {
8289 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8290 {
8291 temp_d=((d->d1&0xFF00)>>8);
8292 temp_d2=(d->d1&0x00FF);
8293
8294 if(last_visible_tab(panel, temp_d, d->w)<(tab_count(panel)-1))
8295 {
8296 ++temp_d;
8297 }
8298
8299 d->d1=(temp_d<<8)|temp_d2;
8300 d->flags|=D_DIRTY;
8301 }
8302 }
8303 }
8304 else
8305 {
8306 d_tab_proc(msg, d, c);
8307 }
8308 font = oldfont;
8309 jwin_tab_proc(MSG_IDLE,d,0);
8310 }
8311 break;
8312
8313 default:
8314 return d_tab_proc(msg, d, c);
8315 break;
8316 }
8317
8318 panel_dialog=(DIALOG *)d->dp3;
8319
8320 if(d->flags & D_HIDDEN)
8321 {
8322 for(i=0; panel[i].text; ++i)
8323 {
8324 for(counter=0; counter<panel[i].objects; counter++)
8325 {
8326 current_object=panel_dialog+(panel[i].dialog[counter]);
8327 current_object->x=zq_screen_w*3;
8328 current_object->y=zq_screen_h*3;
8329 }
8330 }
8331
8332 //d->x=zq_screen_w*3;
8333 //d->y=zq_screen_h*3;
8334 }
8335 else
8336 {
8337 for(i=0; panel[i].text; ++i)
8338 {
8339 for(counter=0; counter<panel[i].objects; counter++)
8340 {
8341 current_object=panel_dialog+(panel[i].dialog[counter]);
8342 current_object->x=panel[i].xy[counter*2];
8343 current_object->y=panel[i].xy[counter*2+1];
8344 }
8345 }
8346
8347 // d->x=zq_screen_w*3;
8348 //d->y=zq_screen_h*3;
8349 }
8350
8351 return broadcast_dialog_message(MSG_IDLE, 0);
8352
8353 // return D_O_K;
8354 }
8355
8356 int32_t discern_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t x)
8357 {
8358 int32_t w=0;
8359
8360 for(size_t i=first_tab; i < panel->getSize(); i++)
8361 {
8362 w+=text_length(font, panel->getName(i))+15;
8363
8364 if(w>x)
8365 {
8366 return i;
8367 }
8368 }
8369
8370 return -1;
8371 }
8372 int32_t tabs_width(GUI::TabPanel *panel)
8373 {
8374 int32_t w=0;
8375
8376 for(size_t i=0; i < panel->getSize(); ++i)
8377 {
8378 w+=text_length(font, panel->getName(i))+15;
8379 }
8380
8381 return w+1;
8382 }
8383 bool uses_tab_arrows(GUI::TabPanel *panel, int32_t maxwidth)
8384 {
8385 return (tabs_width(panel)>maxwidth);
8386 }
8387 size_t last_visible_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8388 {
8389 size_t i;
8390 int32_t w=0;
8391
8392 if(uses_tab_arrows(panel, maxwidth))
8393 {
8394 maxwidth-=28;
8395 }
8396
8397 for(i=first_tab; i < panel->getSize(); ++i)
8398 {
8399 w+=text_length(font, panel->getName(i))+15;
8400
8401 if(w>maxwidth)
8402 {
8403 return i-1;
8404 }
8405 }
8406
8407 return i-1;
8408 }
8409 int32_t displayed_tabs_width(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8410 {
8411 size_t i=0;
8412 int32_t w=0;
8413
8414 for(i=first_tab; i<=last_visible_tab(panel, first_tab, maxwidth); ++i)
8415 {
8416 w+=text_length(font, panel->getName(i))+15;
8417 }
8418
8419 return w+1;
8420 }
8421
8422 INLINE int32_t is_in_rect(int32_t x,int32_t y,int32_t rx1,int32_t ry1,int32_t rx2,int32_t ry2)
8423 {
8424 return x>=rx1 && x<=rx2 && y>=ry1 && y<=ry2;
8425 }
8426
8427 int32_t new_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8428 {
8429 assert(d->flags&D_NEW_GUI);
8430
8431 int32_t tx;
8432 int32_t ret = D_O_K;
8433 int32_t sd=2; //selected delta
8434 static bool skipredraw = false;
8435 GUI::TabPanel *panel=(GUI::TabPanel*)d->dp;
8436 ASSERT(d);
8437
8438 if(d->dp==NULL) return D_O_K;
8439
8440 FONT *oldfont = font;
8441 if(d->dp2)
8442 {
8443 font = (FONT *)d->dp2;
8444 }
8445
8446 switch(msg)
8447 {
8448 case MSG_DRAW:
8449 {
8450 if(skipredraw)
8451 {
8452 skipredraw = false;
8453 ret = D_REDRAW;
8454 break;
8455 }
8456 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8457 {
8458 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8459 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8460 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8461 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8462 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8463 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8464 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8465 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8466 tx=d->x;
8467
8468 if(d->dp)
8469 {
8470 if(panel->getCurrentIndex() != d->d1)
8471 {
8472 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8473 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8474 }
8475
8476 tx+=2;
8477
8478 for(size_t i=d->d1; i < panel->getSize()&&i<=last_visible_tab(panel,d->d1,d->w); ++i)
8479 {
8480 sd=(i==panel->getCurrentIndex())?0:2;
8481
8482 if((i==d->d1) || (i-1 != panel->getCurrentIndex()))
8483 {
8484 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8485 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8486 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8487 }
8488
8489 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcLIGHT]); //top
8490 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcMEDLT]); //top
8491
8492 if(i!=panel->getCurrentIndex())
8493 {
8494 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcLIGHT]); //bottom
8495 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcMEDLT]); //bottom
8496 }
8497 else if(d->flags & D_GOTFOCUS)
8498 {
8499 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8500 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8501 }
8502
8503 tx+=4;
8504 uint8_t* pname = (uint8_t*)(panel->getName(i));
8505 bool dis = panel->getDisabled(i);
8506 if(dis)
8507 gui_textout_ln(screen, pname, tx+5, d->y+sd+5, scheme[jcLIGHT], scheme[jcBOX], 0);
8508 gui_textout_ln(screen, pname, tx+4, d->y+sd+4, scheme[dis ? jcDISABLED_FG : jcBOXFG], dis ? -1 : scheme[jcBOX], 0);
8509 tx+=text_length(font, (const char*)pname)+10;
8510
8511 if((i+1>=panel->getSize()) || (i+1!=panel->getCurrentIndex()))
8512 {
8513 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8514 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8515 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8516 }
8517
8518 tx++;
8519 }
8520
8521 if(d->d1!=0||last_visible_tab(panel,d->d1,d->w)+1<panel->getSize())
8522 {
8523 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8524 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8525 }
8526 }
8527
8528 if((tx+(2-sd))<(d->x+d->w))
8529 {
8530 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8531 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8532 }
8533
8534 }
8535 }
8536 break;
8537
8538 case MSG_WANTFOCUS:
8539 // if(gui_mouse_b())
8540 ret = D_WANTFOCUS|D_REDRAW;
8541 break;
8542 case MSG_GOTFOCUS:
8543 case MSG_LOSTFOCUS:
8544 skipredraw = true;
8545 break;
8546 case MSG_CHAR:
8547 {
8548 int32_t ind = panel->getCurrentIndex();
8549 auto oldind = ind;
8550 switch(c>>8)
8551 {
8552 case KEY_LEFT:
8553 do
8554 {
8555 if(ind > 0)
8556 {
8557 --ind;
8558 }
8559 else
8560 {
8561 ind = panel->getSize()-1;
8562 }
8563 }
8564 while(ind != oldind && panel->getDisabled(ind));
8565 break;
8566 case KEY_RIGHT:
8567 do
8568 {
8569 if(ind+1 < signed(panel->getSize()))
8570 {
8571 ++ind;
8572 }
8573 else
8574 {
8575 ind = 0;
8576 }
8577 }
8578 while(ind != oldind && panel->getDisabled(ind));
8579 break;
8580 default: ind = -1;
8581 }
8582 if(ind > -1 && ind != oldind)
8583 {
8584 panel->switchTo(ind);
8585 GUI_EVENT(d, geCHANGE_SELECTION);
8586 ret |= D_USED_CHAR;
8587 }
8588 }
8589 break;
8590
8591 case MSG_CLICK:
8592 {
8593 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8594 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8595 {
8596 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8597 {
8598 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8599 {
8600 if(d->d1>0)
8601 {
8602 --d->d1;
8603 }
8604
8605 ret |= D_REDRAW;
8606 }
8607 }
8608 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8609 {
8610 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8611 {
8612 size_t t = last_visible_tab(panel, d->d1, d->w);
8613 if(t<(panel->getSize()-1))
8614 {
8615 while(t==last_visible_tab(panel, d->d1, d->w))
8616 ++d->d1;
8617 }
8618
8619 ret |= D_REDRAW;
8620 }
8621 }
8622 }
8623 else if(is_in_rect(gui_mouse_x(),gui_mouse_y(), d->x+2, d->y+2, d->x+displayed_tabs_width(panel,((d->d1&0xFF00)>>8),d->w), d->y+text_height(font)+9))
8624 {
8625 // find out what the new tab (tb) will be (where the mouse is)
8626 int32_t newtab = discern_tab(panel, d->d1, gui_mouse_x()-d->x-2);
8627 if(newtab > -1 && newtab != panel->getCurrentIndex() && !panel->getDisabled(newtab))
8628 {
8629 panel->switchTo(newtab);
8630 GUI_EVENT(d, geCHANGE_SELECTION);
8631 }
8632 }
8633 }
8634 break;
8635 }
8636 font = oldfont;
8637 return ret;
8638 }
8639
8640
8641
8642
8643 int32_t jwin_hline_proc(int32_t msg, DIALOG *d, int32_t)
8644 {
8645 ASSERT(d);
8646
8647 if(msg==MSG_DRAW)
8648 {
8649 if(d->w < 1) return D_O_K;
8650 for(int q = 0; q <= d->d1; ++q)
8651 {
8652 if(d->d2&1)
8653 {
8654 hline(screen, d->x, d->y+q, d->x+d->w-1, d->fg);
8655 }
8656 else
8657 {
8658 hline(screen, d->x, d->y-q, d->x+d->w-1, scheme[jcMEDDARK]);
8659 hline(screen, d->x, d->y+1+q, d->x+d->w-1, scheme[jcLIGHT]);
8660 }
8661 }
8662 }
8663
8664 return D_O_K;
8665 }
8666
8667 int32_t jwin_vline_proc(int32_t msg, DIALOG *d, int32_t)
8668 {
8669 ASSERT(d);
8670
8671 if(msg==MSG_DRAW)
8672 {
8673 if(d->h < 1) return D_O_K;
8674 for(int q = 0; q <= d->d1; ++q)
8675 {
8676 if(d->d2&1)
8677 {
8678 vline(screen, d->x+q, d->y, d->y+d->h-1, d->fg);
8679 }
8680 else
8681 {
8682 vline(screen, d->x+q, d->y, d->y+d->h-1, scheme[jcMEDDARK]);
8683 vline(screen, d->x+1-q, d->y, d->y+d->h-1, scheme[jcLIGHT]);
8684 }
8685 }
8686 }
8687
8688 return D_O_K;
8689 }
8690
8691 int32_t jwin_editbox_proc(int32_t msg, DIALOG *d, int32_t c)
8692 {
8693 return d_editbox_proc(msg, d, c);
8694 }
8695
8696 //centers dialog based on first object, which should be the containing window
8697 3938 void jwin_center_dialog(DIALOG *dialog)
8698 {
8699 int32_t xc, yc;
8700 int32_t c;
8701 ASSERT(dialog);
8702
8703 /* how much to move by? */
8704 3938 xc = (zq_screen_w - dialog[0].w) / 2 - dialog[0].x;
8705 3938 yc = (zq_screen_h - dialog[0].h) / 2 - dialog[0].y;
8706
8707 /* move it */
8708
2/2
✓ Branch 0 taken 82980 times.
✓ Branch 1 taken 3938 times.
86918 for(c=0; dialog[c].proc; c++)
8709 {
8710 82980 dialog[c].x += xc;
8711 82980 dialog[c].y += yc;
8712 82980 }
8713 3938 }
8714 //up-left aligns dialog based on first object, which should be the containing window
8715 void jwin_ulalign_dialog(DIALOG *dialog)
8716 {
8717 int32_t xc, yc;
8718 int32_t c;
8719 ASSERT(dialog);
8720
8721 /* how much to move by? */
8722 xc = dialog[0].x;
8723 yc = dialog[0].y;
8724
8725 /* move it */
8726 for(c=0; dialog[c].proc; c++)
8727 {
8728 dialog[c].x -= xc;
8729 dialog[c].y -= yc;
8730 }
8731 }
8732
8733 //Custom slider proc
8734 int32_t d_jslider_proc(int32_t msg, DIALOG *d, int32_t c)
8735 {
8736 BITMAP *gui_bmp = screen;
8737 BITMAP *slhan = NULL;
8738 int32_t oldpos, newpos;
8739 int32_t sfg; /* slider foreground color */
8740 int32_t vert = TRUE; /* flag: is slider vertical? */
8741 int32_t hh = 7; /* handle height (width for horizontal sliders) */
8742 int32_t hmar; /* handle margin */
8743 int32_t slp; /* slider position */
8744 int32_t mp; /* mouse position */
8745 int32_t irange;
8746 int32_t slx, sly, slh, slw;
8747 int32_t msx, msy;
8748 int32_t retval = D_O_K;
8749 int32_t upkey, downkey;
8750 int32_t pgupkey, pgdnkey;
8751 int32_t homekey, endkey;
8752 int32_t delta;
8753 fixed slratio, slmax, slpos;
8754 typedef int32_t (*SLIDER_TYPE)(void*, int32_t);
8755 SLIDER_TYPE proc = NULL;
8756 //int32_t (*proc)(void *cbpointer, int32_t d2value);
8757 int32_t oldval;
8758 ASSERT(d);
8759
8760 /* check for slider direction */
8761 if(d->h < d->w)
8762 vert = FALSE;
8763
8764 /* set up the metrics for the control */
8765 if(d->dp != NULL)
8766 {
8767 slhan = (BITMAP *)d->dp;
8768
8769 if(vert)
8770 hh = slhan->h;
8771 else
8772 hh = slhan->w;
8773 }
8774
8775 hmar = hh/2;
8776 irange = (vert) ? d->h : d->w;
8777 slmax = itofix(irange-hh);
8778 slratio = slmax / (d->d1);
8779 slpos = slratio * d->d2;
8780 slp = fixtoi(slpos);
8781
8782 switch(msg)
8783 {
8784
8785 case MSG_DRAW:
8786 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8787
8788 if(vert)
8789 {
8790 rectfill(gui_bmp, d->x, d->y, d->x+d->w/2-2, d->y+d->h-1, d->bg);
8791 rectfill(gui_bmp, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h-1, sfg);
8792 rectfill(gui_bmp, d->x+d->w/2+2, d->y, d->x+d->w-1, d->y+d->h-1, d->bg);
8793 }
8794 else
8795 {
8796 rectfill(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h/2-2, d->bg);
8797 rectfill(gui_bmp, d->x, d->y+d->h/2-1, d->x+d->w-1, d->y+d->h/2+1, sfg);
8798 rectfill(gui_bmp, d->x, d->y+d->h/2+2, d->x+d->w-1, d->y+d->h-1, d->bg);
8799 }
8800
8801 /* okay, background and slot are drawn, now draw the handle */
8802 if(slhan)
8803 {
8804 if(vert)
8805 {
8806 slx = d->x+(d->w/2)-(slhan->w/2);
8807 sly = d->y+(d->h-1)-(hh+slp);
8808 }
8809 else
8810 {
8811 slx = d->x+slp;
8812 sly = d->y+(d->h/2)-(slhan->h/2);
8813 }
8814
8815 draw_sprite(gui_bmp, slhan, slx, sly);
8816 }
8817 else
8818 {
8819 /* draw default handle */
8820 if(vert)
8821 {
8822 slx = d->x;
8823 sly = d->y+(d->h)-(hh+slp);
8824 slw = d->w-1;
8825 slh = hh-1;
8826 }
8827 else
8828 {
8829 slx = d->x+slp;
8830 sly = d->y;
8831 slw = hh-1;
8832 slh = d->h-1;
8833 }
8834
8835 /* draw body */
8836 rectfill(gui_bmp, slx+2, sly, slx+(slw-2), sly+slh, sfg);
8837 vline(gui_bmp, slx+1, sly+1, sly+slh-1, sfg);
8838 vline(gui_bmp, slx+slw-1, sly+1, sly+slh-1, sfg);
8839 vline(gui_bmp, slx, sly+2, sly+slh-2, sfg);
8840 vline(gui_bmp, slx+slw, sly+2, sly+slh-2, sfg);
8841 vline(gui_bmp, slx+1, sly+2, sly+slh-2, d->bg);
8842 hline(gui_bmp, slx+2, sly+1, slx+slw-2, d->bg);
8843 putpixel(gui_bmp, slx+2, sly+2, d->bg);
8844 }
8845
8846 if(d->flags & D_GOTFOCUS)
8847 dotted_rect(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h-1, sfg, d->bg);
8848
8849 break;
8850
8851 case MSG_WANTFOCUS:
8852 case MSG_LOSTFOCUS:
8853 return D_WANTFOCUS;
8854
8855 case MSG_KEY:
8856 if(!(d->flags & D_GOTFOCUS))
8857 return D_WANTFOCUS;
8858 else
8859 return D_O_K;
8860
8861 case MSG_CHAR:
8862 /* handle movement keys to move slider */
8863 c >>= 8;
8864
8865 if(vert)
8866 {
8867 upkey = KEY_UP;
8868 downkey = KEY_DOWN;
8869 pgupkey = KEY_PGUP;
8870 pgdnkey = KEY_PGDN;
8871 homekey = KEY_END;
8872 endkey = KEY_HOME;
8873 }
8874 else
8875 {
8876 upkey = KEY_RIGHT;
8877 downkey = KEY_LEFT;
8878 pgupkey = KEY_PGDN;
8879 pgdnkey = KEY_PGUP;
8880 homekey = KEY_HOME;
8881 endkey = KEY_END;
8882 }
8883
8884 if(c == upkey)
8885 delta = 1;
8886 else if(c == downkey)
8887 delta = -1;
8888 else if(c == pgdnkey)
8889 delta = -d->d1 / 16;
8890 else if(c == pgupkey)
8891 delta = d->d1 / 16;
8892 else if(c == homekey)
8893 delta = -d->d2;
8894 else if(c == endkey)
8895 delta = d->d1 - d->d2;
8896 else
8897 delta = 0;
8898
8899 if(delta)
8900 {
8901 oldpos = slp;
8902 oldval = d->d2;
8903
8904 //while (true) {
8905 for(; ;) //thank you, MSVC ~pkmnfrk
8906 {
8907 d->d2 = d->d2+delta;
8908 slpos = slratio*d->d2;
8909 slp = fixtoi(slpos);
8910
8911 if((slp != oldpos) || (d->d2 <= 0) || (d->d2 >= d->d1))
8912 break;
8913 }
8914
8915 if(d->d2 < 0)
8916 d->d2 = 0;
8917
8918 if(d->d2 > d->d1)
8919 d->d2 = d->d1;
8920
8921 retval = D_USED_CHAR;
8922
8923 if(d->d2 != oldval)
8924 {
8925 /* call callback function here */
8926 if(d->dp2)
8927 {
8928 proc = (SLIDER_TYPE)(d->dp2);
8929 retval |= (*proc)(d->dp3, d->d2);
8930 }
8931
8932 GUI_EVENT(d, geCHANGE_VALUE);
8933
8934 object_message(d, MSG_DRAW, 0);
8935 }
8936 }
8937
8938 break;
8939
8940 case MSG_WANTWHEEL:
8941 return 1;
8942
8943 case MSG_WHEEL:
8944 oldval = d->d2;
8945 d->d2 = MID(0, d->d2+c, d->d1);
8946
8947 if(d->d2 != oldval)
8948 {
8949 /* call callback function here */
8950 if(d->dp2)
8951 {
8952 proc = (SLIDER_TYPE)(d->dp2);
8953 retval |= (*proc)(d->dp3, d->d2);
8954 }
8955
8956 GUI_EVENT(d, geCHANGE_VALUE);
8957 object_message(d, MSG_DRAW, 0);
8958 retval |= D_REDRAWME;
8959 }
8960
8961 break;
8962
8963 case MSG_CLICK:
8964 /* track the mouse until it is released */
8965 mp = slp;
8966
8967 while(gui_mouse_b())
8968 {
8969 msx = gui_mouse_x();
8970 msy = gui_mouse_y();
8971 oldval = d->d2;
8972
8973 if(vert)
8974 mp = (d->y+d->h-hmar)-msy;
8975 else
8976 mp = msx-(d->x+hmar);
8977
8978 if(mp < 0)
8979 mp = 0;
8980
8981 if(mp > irange-hh)
8982 mp = irange-hh;
8983
8984 slpos = itofix(mp);
8985 slmax = fixdiv(slpos, slratio);
8986 newpos = fixtoi(slmax);
8987
8988 if(newpos != oldval)
8989 {
8990 d->d2 = newpos;
8991
8992 /* call callback function here */
8993 if(d->dp2 != NULL)
8994 {
8995 proc = (SLIDER_TYPE)(d->dp2);
8996 retval |= (*proc)(d->dp3, d->d2);
8997 }
8998
8999 GUI_EVENT(d, geCHANGE_VALUE);
9000 object_message(d, MSG_DRAW, 0);
9001 }
9002
9003 /* let other objects continue to animate */
9004 broadcast_dialog_message(MSG_IDLE, 0);
9005 update_hw_screen();
9006 }
9007
9008 break;
9009 }
9010
9011 return retval;
9012 }
9013
9014 // This is only used by jwin_check_proc and jwin_radio_proc.
9015 int32_t d_jwinbutton_proc(int32_t msg, DIALOG *d, int32_t)
9016 {
9017 BITMAP *gui_bmp;
9018 int32_t state1, state2;
9019 int32_t black;
9020 int32_t swap;
9021 int32_t g;
9022 ASSERT(d);
9023
9024 gui_bmp = screen;
9025
9026 switch(msg)
9027 {
9028 case MSG_DRAW:
9029 {
9030 if(d->flags & D_SELECTED)
9031 {
9032 g = 1;
9033 state1 = d->bg;
9034 state2 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
9035 }
9036 else
9037 {
9038 g = 0;
9039 state1 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
9040 state2 = d->bg;
9041 }
9042
9043 rectfill(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state2);
9044 rect(gui_bmp, d->x+g, d->y+g, d->x+d->w-2+g, d->y+d->h-2+g, state1);
9045 gui_textout_ex(gui_bmp, (char *)d->dp, d->x+d->w/2+g, d->y+d->h/2-text_height(font)/2+g, state1, -1, TRUE);
9046
9047 if(d->flags & D_SELECTED)
9048 {
9049 vline(gui_bmp, d->x, d->y, d->y+d->h-2, d->bg);
9050 hline(gui_bmp, d->x, d->y, d->x+d->w-2, d->bg);
9051 }
9052 else
9053 {
9054 black = makecol(0,0,0);
9055 vline(gui_bmp, d->x+d->w-1, d->y+1, d->y+d->h-2, black);
9056 hline(gui_bmp, d->x+1, d->y+d->h-1, d->x+d->w-1, black);
9057 }
9058
9059 if((d->flags & D_GOTFOCUS) &&
9060 (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT)))
9061 dotted_rect(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state1, state2);
9062
9063 break;
9064 }
9065 case MSG_WANTFOCUS:
9066 return D_WANTFOCUS;
9067
9068 case MSG_KEY:
9069 {
9070 /* close dialog? */
9071 if(d->flags & D_EXIT)
9072 {
9073 return D_CLOSE;
9074 }
9075
9076 /* or just toggle */
9077 d->flags ^= D_SELECTED;
9078 GUI_EVENT(d, geTOGGLE);
9079 object_message(d, MSG_DRAW, 0);
9080 break;
9081 }
9082
9083 case MSG_CLICK:
9084 {
9085 /* what state was the button originally in? */
9086 state1 = d->flags & D_SELECTED;
9087
9088 swap = state1;
9089
9090 /* track the mouse until it is released */
9091 while(gui_mouse_b())
9092 {
9093 state2 = ((gui_mouse_x() >= d->x) && (gui_mouse_y() >= d->y) &&
9094 (gui_mouse_x() < d->x + d->w) && (gui_mouse_y() < d->y + d->h));
9095
9096 if(swap)
9097 state2 = !state2;
9098
9099 /* redraw? */
9100 bool should_redraw = false;
9101 if(((state1) && (!state2)) || ((state2) && (!state1)))
9102 {
9103 d->flags ^= D_SELECTED;
9104 GUI_EVENT(d, geTOGGLE);
9105 state1 = d->flags & D_SELECTED;
9106 object_message(d, MSG_DRAW, 0);
9107 should_redraw = true;
9108 }
9109
9110 /* let other objects continue to animate */
9111 int r = broadcast_dialog_message(MSG_IDLE, 0);
9112 if (r & D_REDRAWME) should_redraw = true;
9113
9114 if (should_redraw)
9115 {
9116 update_hw_screen();
9117 }
9118 }
9119
9120 if(d->dp3 != NULL)
9121 {
9122 //object_message(d, MSG_DRAW, 0);
9123 typedef int32_t (*funcType)(void);
9124 funcType func=reinterpret_cast<funcType>(d->dp3);
9125
9126 return func();
9127 }
9128
9129 /* should we close the dialog? */
9130 if(d->flags & D_EXIT)
9131 {
9132 return D_CLOSE;
9133 }
9134 break;
9135 }
9136 }
9137
9138 return D_O_K;
9139 }
9140
9141 //Misc bitmap drawing
9142 void draw_x(BITMAP* dest, int x1, int y1, int x2, int y2, int color)
9143 {
9144 line(dest, x1, y1, x2, y2, color);
9145 line(dest, x1, y2, x2, y1, color);
9146 }
9147
9148 void draw_check(BITMAP* dest, int x1, int y1, int x2, int y2, int c)
9149 {
9150 if(x2 < x1)
9151 zc_swap(x2,x1);
9152 if(y2 < y1)
9153 zc_swap(y2,y1);
9154 int x3 = ((x2-x1)/2)+x1;
9155 int y3 = y2-(x3-x1);
9156 line(dest, x1, y3, x3, y2, c);
9157 line(dest, x3, y2, x2, y1, c);
9158 }
9159
9160 void draw_checkerboard(BITMAP* dest, int x, int y, int sz, optional<int> cb_sz, int offx, int offy)
9161 {
9162 if(!cb_sz)
9163 cb_sz = sz/2;
9164 int ox = -x+offx, oy = -y+offy;
9165 ditherrectfill(dest, x, y, x+sz-1, y+sz-1, vc(CheckerCol1), dithChecker, *cb_sz, ox, oy, vc(CheckerCol2));
9166 }
9167
9168 int32_t d_vsync_proc(int32_t msg,DIALOG *d,int32_t c)
9169 {
9170 // This use to be what kept 60fps, but now render_timer_wait handles that.
9171 switch(msg)
9172 {
9173 case MSG_IDLE:
9174 {
9175 broadcast_dialog_message(MSG_VSYNC, c);
9176 if(d->dp)
9177 {
9178 int32_t ret = (*(std::function<int32_t()>*)d->dp)();
9179 switch(ret)
9180 {
9181 case ONTICK_EXIT:
9182 if(d->flags&D_NEW_GUI)
9183 close_new_gui_dlg(d);
9184 return D_EXIT;
9185 case ONTICK_CLOSE:
9186 if(d->flags&D_NEW_GUI)
9187 {
9188 //Simulate a GUI_EVENT for the window proc
9189 DIALOG* window = d-1;
9190 while(window->proc != jwin_win_proc) --window;
9191 int32_t ret = new_gui_event(window-1, geCLOSE);
9192 if(ret >= 0)
9193 return ret;
9194 }
9195 return D_EXIT;
9196 case ONTICK_REDRAW:
9197 return D_REDRAW;
9198 }
9199 }
9200 break;
9201 }
9202 }
9203
9204 return D_O_K;
9205 }
9206
9207 //
9208
9209 void draw_checkbox(BITMAP *dest,int x,int y,int sz,bool value)
9210 {
9211 draw_checkbox(dest,x,y,sz,sz,value);
9212 }
9213 void draw_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9214 {
9215 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9216 rectfill(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTBG]);
9217
9218 if(value)
9219 {
9220 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9221 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9222 }
9223 }
9224 void draw_dis_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9225 {
9226 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9227
9228 if(value)
9229 {
9230 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9231 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9232 }
9233 }
9234
9235 bool do_scheckbox(BITMAP *dest,int x,int y,int sz,int &value, int xoffs, int yoffs)
9236 {
9237 return do_checkbox(dest,x,y,sz,sz,value,xoffs,yoffs);
9238 }
9239 bool do_checkbox(BITMAP *dest,int x,int y,int wid,int hei,int &value, int xoffs, int yoffs)
9240 {
9241 bool over=false;
9242
9243 while(gui_mouse_b())
9244 {
9245 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1,y+hei-1))
9246 {
9247 if(!over)
9248 {
9249 value=value?0:1;
9250 draw_checkbox(dest,x,y,wid,hei,value!=0);
9251 over=true;
9252 update_hw_screen();
9253 }
9254 }
9255 else
9256 {
9257 if(over)
9258 {
9259 value=value?0:1;
9260 draw_checkbox(dest,x,y,wid,hei,value!=0);
9261 over=false;
9262 update_hw_screen();
9263 }
9264 }
9265 rest(1);
9266 }
9267
9268 return over;
9269 }
9270 bool do_checkbox_tx(BITMAP *dest,int x,int y,int wid,int hei,int &value, int txtoffs, int xoffs, int yoffs)
9271 {
9272 bool over=false;
9273
9274 while(gui_mouse_b())
9275 {
9276 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1+txtoffs,y+hei-1))
9277 {
9278 if(!over)
9279 {
9280 value=value?0:1;
9281 draw_checkbox(dest,x,y,wid,hei,value!=0);
9282 over=true;
9283 update_hw_screen();
9284 }
9285 }
9286 else
9287 {
9288 if(over)
9289 {
9290 value=value?0:1;
9291 draw_checkbox(dest,x,y,wid,hei,value!=0);
9292 over=false;
9293 update_hw_screen();
9294 }
9295 }
9296 rest(1);
9297 }
9298
9299 return over;
9300 }
9301
9302 //box_out stuff
9303 static int32_t box_x = 0;
9304 static int32_t box_y = 0;
9305 static bool box_active=false;
9306 static int32_t box_store_x = 0;
9307 439 static FONT *box_title_font=font;
9308 439 static FONT *box_message_font=font;
9309 static int32_t box_style=0;
9310 static int32_t box_titlebar_height=0;
9311 static int32_t box_message_height=0;
9312 static uint8_t box_text_scale=1;
9313 static int32_t box_w=304;
9314 static int32_t box_h=176;
9315 static int32_t box_l=8;
9316 static int32_t box_r=312;
9317 static int32_t box_t=32;
9318 static int32_t box_b=208;
9319 static bool box_log=true;
9320 static char box_log_msg[480];
9321 static int32_t box_msg_pos=0;
9322 static int32_t box_store_pos=0;
9323
9324 int32_t onSnapshot2()
9325 {
9326 char buf[20];
9327 int32_t num=0;
9328
9329 do
9330 {
9331 sprintf(buf, "zelda%03d.bmp", ++num);
9332 }
9333 while(num<999 && exists(buf));
9334
9335 PALETTE temppal;
9336 get_palette(temppal);
9337 BITMAP *tempbmp=create_bitmap_ex(8,screen->w, screen->h);
9338 blit(screen,tempbmp,0,0,0,0,screen->w,screen->h);
9339 save_bitmap(buf,screen,temppal);
9340 destroy_bitmap(tempbmp);
9341 return D_O_K;
9342 }
9343
9344 void set_default_box_size()
9345 {
9346 int32_t screen_w = screen->w;
9347 int32_t screen_h = screen->h;
9348
9349 box_w=MIN(512, screen_w-16);
9350 box_h=MIN(256, (screen_h-64)&0xFFF0);
9351
9352 box_l=(screen_w-box_w)/2;
9353 box_t=(screen_h-box_h)/2;
9354 box_r=box_l+box_w;
9355 box_b=box_t+box_h;
9356 }
9357 /* resizes the box */
9358 void set_box_size(int32_t w, int32_t h)
9359 {
9360 int32_t screen_w = zq_screen_w;
9361 int32_t screen_h = zq_screen_h;
9362
9363 if(w <= 0) w = 512;
9364 if(h <= 0) h = 256;
9365 box_w=MIN(w, screen_w-16);
9366 box_h=MIN(h, (screen_h-64)&0xFFF0);
9367
9368 box_l=(screen_w-box_w)/2;
9369 box_t=(screen_h-box_h)/2;
9370 box_r=box_l+box_w;
9371 box_b=box_t+box_h;
9372 }
9373
9374 /* starts outputting a progress message */
9375 9 void box_start(int32_t style, const char *title, FONT *title_font, FONT *message_font, bool log, int32_t w, int32_t h, uint8_t scale)
9376 {
9377
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (is_headless())
9378 9 return;
9379
9380 box_text_scale=scale;
9381 box_style=style;
9382 box_title_font=(title_font!=NULL)?title_font:font;
9383 box_message_font=(message_font!=NULL)?message_font:font;
9384 box_message_height=text_height(box_message_font)*scale;
9385 box_titlebar_height=title?text_height(box_title_font)+2:0;
9386 set_box_size(w,h);
9387 /*
9388 box_w=BOX_W;
9389 box_h=BOX_H;
9390 box_l=BOX_L;
9391 box_r=BOX_R;
9392 box_t=BOX_T;
9393 box_b=BOX_B;
9394 */
9395 box_log=log;
9396 memset(box_log_msg, 0, 480);
9397 box_msg_pos=0;
9398 box_store_pos=0;
9399
9400 if(!box_active)
9401 popup_zqdialog_start();
9402 jwin_draw_win(screen, box_l, box_t, box_r-box_l, box_b-box_t, FR_WIN);
9403
9404 if(title!=NULL)
9405 {
9406 zc_swap(font,box_title_font);
9407 jwin_draw_titlebar(screen, box_l+3, box_t+3, box_r-box_l-6, 18, title, false);
9408 zc_swap(font,box_title_font);
9409 box_titlebar_height=18;
9410 }
9411
9412
9413 box_store_x = box_x = box_y = 0;
9414 box_active = true;
9415 box_t+=box_titlebar_height;
9416 box_h-=box_titlebar_height;
9417 box_log=log;
9418 memset(box_log_msg, 0, 480);
9419 box_msg_pos=0;
9420 box_store_pos=0;
9421 9 }
9422
9423 /* outputs text to the progress message */
9424 30973 void box_out(const char *msg)
9425 {
9426
1/2
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
30973 string remainder = "";
9427
1/2
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
30973 string temp(msg);
9428
9429
1/2
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
30973 if(box_active)
9430 {
9431 //do primitive text wrapping
9432 uint32_t i;
9433 for(i=0; i<temp.size(); i++)
9434 {
9435 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str())*box_text_scale;
9436
9437 if(length > box_r-box_l-16)
9438 {
9439 i = zc_max(i-1,0);
9440 break;
9441 }
9442 }
9443
9444 set_clip_rect(screen, box_l+8, box_t+1, box_r-8, box_b-1);
9445 if(box_text_scale == 1)
9446 textout_ex(screen, box_message_font, temp.substr(0,i).c_str(), box_l+8+box_x, box_t+(box_y+1)*box_message_height, gui_fg_color, gui_bg_color);
9447 else
9448 {
9449 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str());
9450 BITMAP* tempbit = create_bitmap_ex(8, length, box_message_height);
9451 clear_bitmap(tempbit);
9452 textout_ex(tempbit, box_message_font, temp.substr(0,i).c_str(), 0, 0, gui_fg_color, gui_bg_color);
9453 stretch_blit(tempbit, screen, 0, 0, length, box_message_height/box_text_scale, box_l+8+box_x, box_t+(box_y+1)*box_message_height, length*box_text_scale, box_message_height);
9454 destroy_bitmap(tempbit);
9455 }
9456 set_clip_rect(screen, 0, 0, screen->w-1, screen->h-1);
9457 remainder = temp.substr(i,temp.size()-i);
9458 }
9459
9460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30973 times.
30973 if(box_log)
9461 {
9462 30973 sprintf(box_log_msg+box_msg_pos, "%s", msg);
9463 30973 }
9464
9465
1/2
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
30973 box_x += text_length(box_message_font, msg);
9466 30973 box_msg_pos+=(int32_t)strlen(msg);
9467
9468
2/4
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30973 times.
30973 if(remainder != "")
9469 {
9470 bool oldlog = box_log;
9471 box_log = false;
9472 box_eol();
9473 box_out(remainder.c_str());
9474 box_log = oldlog;
9475 }
9476
9477 // For web, always call update_hw_screen because it yields to the main thread,
9478 // which makes long running tasks like loading a quest not block the main thread,
9479 // which would make SFX sound awful on the title screen.
9480
3/6
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30973 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30973 times.
30973 if (box_active || is_web())
9481 update_hw_screen();
9482 30973 }
9483
9484 /* calls box_out, and box_eol for newlines */
9485 void box_out_nl(const char *msg)
9486 {
9487 string line;
9488 istringstream reader(msg);
9489 while (getline(reader, line))
9490 {
9491 box_out(line.c_str());
9492 box_eol();
9493 }
9494 }
9495
9496 /* remembers the current x position */
9497 492 void box_save_x()
9498 {
9499
1/2
✓ Branch 0 taken 492 times.
✗ Branch 1 not taken.
492 if(box_active)
9500 {
9501 box_store_x=box_x;
9502 }
9503
9504 492 box_store_pos=box_msg_pos;
9505 492 }
9506
9507 /* remembers the current x position */
9508 156 void box_load_x()
9509 {
9510
1/2
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
156 if(box_active)
9511 {
9512 box_x=box_store_x;
9513 }
9514
9515 156 box_msg_pos=box_store_pos;
9516 156 }
9517
9518 /* outputs text to the progress message */
9519 16221 void box_eol()
9520 {
9521
1/2
✓ Branch 0 taken 16221 times.
✗ Branch 1 not taken.
16221 if(box_active)
9522 {
9523 box_x = 0;
9524 box_y++;
9525
9526 if((box_y+2)*box_message_height >= box_h)
9527 {
9528 blit(screen, screen, box_l+8, box_t+(box_message_height*2), box_l+8, box_t+(box_message_height), box_w-16, box_y*box_message_height);
9529 rectfill(screen, box_l+8, box_t+box_y*box_message_height, box_l+box_w-8, box_t+(box_y+1)*box_message_height, gui_bg_color);
9530 box_y--;
9531 }
9532 }
9533
9534 16221 box_msg_pos = 0;
9535
9536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16221 times.
16221 if(box_log)
9537 {
9538 16221 al_trace("%s", box_log_msg);
9539 16221 al_trace("\n");
9540 16221 memset(box_log_msg, 0, 480);
9541 16221 }
9542
9543
1/2
✓ Branch 0 taken 16221 times.
✗ Branch 1 not taken.
16221 if (box_active)
9544 update_hw_screen();
9545 16221 }
9546
9547 /* ends output of a progress message */
9548 833 void box_end(bool pause)
9549 {
9550
1/2
✓ Branch 0 taken 833 times.
✗ Branch 1 not taken.
833 if(box_active)
9551 {
9552 if(pause)
9553 {
9554 box_eol();
9555 box_pause();
9556 }
9557
9558 box_active = false;
9559 popup_zqdialog_end();
9560 }
9561 833 }
9562
9563 /* pauses box output */
9564 void box_pause()
9565 {
9566 if(box_active)
9567 {
9568 box_save_x();
9569 box_out("-- press a key --");
9570
9571 while(gui_mouse_b()) rest(1);
9572 while(!(keypressed() || gui_mouse_b())) rest(1);
9573 while(gui_mouse_b()) rest(1);
9574
9575 clear_keybuf();
9576 box_load_x();
9577 }
9578 }
9579